Workarund missing Union support in Kotlin - kotlin

I wonder if there is any better solution to my Problem.
I have a Service1 that handles two different input types (A|B) using method overloading.
A Service2 should provide a method that accepts all input types of Service1 and does some work with the result, which I do not want to duplicate.
I came up with two solutions, but neither of those is convincing to me.
data class A(...)
data class B(...)
class C
class Service1 {
fun doSomething(input: A): C {}
fun doSomething(input: B): C {}
}
// Solution 1
class Service2_v1 {
private val service: Service1
fun <T>doThings(input: T) {
val result = when(input) {
is A -> service.doSomething(input)
is B -> service.doSomething(input)
else -> throw IllegalArgumentException()
}
...work with result
}
}
// Solution2
class Service2_v2 {
private val service: Service1
fun doThings(input: A) = handleResult(service.doSomething(input))
fun doThings(input: B) = handleResult(service.doSomething(input))
private fun handleResult(result: C) {
...work with result
}
}
Since this only needs to work with Types that are known at compile type, I wonder if there is a cleaner solution with generics, similar to this pseudo code:
class Service2_notWorking {
private val service: Service1
fun <T : ArgumentTypeOf<Service1.doSometing>>doThings(input: T) {
val result = service.doSomething(input)
...work with result
}
}

Related

How to enforce relationship between Kotlin classes

Im new to Kotlin and investigating what is/isnt possible
I have a use case as follows:-
As a technical exercise I am attempting to model remote API requests and responses, and enforce relationships between them
My goal is to be able to declare the relationship between Requests and Responses in a clear and succinct way at the top of a Class. This will 1). document the API calls made by this Class, 2). Enforce the relationship so that Request1 can only produce Response1
Pseudo code:-
Requests {
Request1 -> Response1
Request2 -> Response2
...
RequestN -> ResponseN
}
I have defined two interfaces Request & Response and employ them as follows:-
interface Request {
fun <T> response(data : T): Lazy<Response>
}
interface Response
data class Request1(val request: String) : Request {
data class Response1(val output: String) : Response
override fun <T> response(data: T): Lazy<Response> {
return lazy { Response1(data as String) }
}
}
data class Request2(val request: Long) : Request {
data class Response2(val output: Double) : Response
override fun <T> response(data: T): Lazy<Response> {
return lazy { Response2(data as Double) }
}
}
I have a Controller class that makes the API calls as follows:-
class Controller {
fun call(request: Request): Lazy<Response> {
return when (request) {
is Request1 -> request.response("Testing Data")
is Request2 -> request.response(Math.PI)
else -> TODO()
}
}
}
Using the above data classes I can enforce that Request1 is linked to only Response1 and also specify the response data type wrapped by each Response.
Although the above classes provide the functionality and adhere to these rules, they are verbose.
Is there a more succinct approach I could employ to obtain the desired result.
The reason I require this is I am looking for "Self Documenting" code, where a developer can view the definition of Request/Response pairs and association rules and clearly see what is intended.
For example: A developer looking at the final Request definitions can clearly see that Response1 with be generated by Request1. I also want to enforce that Response1 can only ever be produced from Request1.
My example above is simplified, as in "The Real World" the data wrapped by each Response will be sourced from the actual API request call, I have illustrated with "Hard Coded".
I would much rather define Request1 and Response1 on a single line if possible.
UPDATE
I have refactored my original classes as follows:-
interface Request<ResponseData> {
fun response(data: ResponseData): Lazy<Response>
}
interface Response
sealed class Requests<T> : Request<T> {
data class Request1(val request: String) : Requests<String>() {
inner class Response1(val output: String) : Response
override fun response(data: String): Lazy<Response> {
return lazy { Response1(data) }
}
}
data class Request2(val request: Long) : Requests<Double>() {
inner class Response2(val output: Double) : Response
override fun response(data: Double): Lazy<Response> {
return lazy { Response2(data) }
}
}
}
class Controller {
fun <T> call(request: Request<T>): Lazy<Response> {
return when (request) {
is Requests.Request1 -> request.response("Testing Data")
is Requests.Request2 -> request.response(Math.PI)
else -> TODO()
}
}
}
While this version of my code has many benefits from the original, one feature I am still not happy with is that each Request/Response declaration is still quite verbose, e.g. it requires 5 lines of code. Is there an approach I can employ to make each Request/Response pair declaration more succinct?, e.g. take up fewer lines of code.
UPDATE II
Im attempting to refactor my sealed class above so that the overridden function response is defined in the outer sealed class.
interface Request<ResponseData> {
fun response(data: ResponseData): Lazy<Response>
}
interface Response
sealed class Requests<T> : Request<T> {
data class Request1(val request: String) : Requests<String>() {
inner class Response1(val output: String) : Response
}
data class Request2(val request: Long) : Requests<Double>() {
inner class Response2(val output: Double) : Response
}
override fun response(data: T): Lazy<Response> {
return lazy { // What implementation goes here??? // }
}
}
Is this approach possible?
How do I refer to the individual concrete ResponseN classes in the outer sealed class?
Another approach:
data class Box<T, V>(val req: T, val rsp: V)
interface Interaction<RequestT, ResponseT> {
val req: RequestT
fun exec(): Box<RequestT, ResponseT>
}
sealed class Interactions<RequestT, ResponseT> : Interaction<RequestT, ResponseT> {
class Interaction1(override val req: String) : Interaction<String, String> {
override fun exec() = Box(req, "by")
}
class Interaction2(override val req: Long) : Interaction<Long, Double> {
override fun exec() = Box(req, 1.0)
}
}
fun main() {
val interaction1 = Interactions.Interaction1("hi")
val interaction2 = Interactions.Interaction2(42)
println(interaction1.exec()) // Box(req=hi, rsp=by)
println(interaction2.exec()) // Box(req=42, rsp=1.0)
}
Maybe your example is simplified from what you're actually doing, but I don't see the purpose of the Response interface, or the need for separate Request implementations to achieve what your code does:
data class Request<T>(val request: String, val responseType: KClass<out T>) {
fun response(data : T) = lazy { data }
}
class Controller {
fun <T: Any> call(request: Request<T>): Lazy<T> {
#Suppress("UNCHECKED_CAST")
return when (request.responseType) {
String::class -> request.response("Testing Data" as T)
Double::class -> request.response(Math.PI as T)
else -> TODO()
}
}
}
It's kind of an odd use of Lazy though, since you are wrapping a pre-computed value.
My goal is to be able to declare the relationship between Requests and Responses in a clear and succinct way at the top of a Class. This will 1). document the API calls made by this Class, 2). Enforce the relationship so that Request1 can only produce Response1
A great way to enforce the relationships is to separate the interface and implementation levels. Currently you have your interface defined as
interface Request {
fun <T> response(data : T): Lazy<Response>
}
And it does not tell you that the response can vary. It's high level and then you define actual relations in your implementation.
I suggest to decouple relations and the implementation by moving the relations to the interface level.
Here is my suggestion. Forgive me if something does not compile, I'm writing the code from my head, I want to communicate the design ideas and you may have to change some pseudocode.
Let's start with the interface:
interface Response
interface Request // I see that you are using primitive types for requests, so you don't need the interface. But in a real world scenario your requests will probably be more complex than primitive types and then it will make sense to wrap them in this interface. It also makes the code easier to understand - a string can be anything, while a Request is definitely a request.
// This is an interface that actually performs a request, so makes sense to name it in an actionable way
interface Requester<T, M> {
fun <in T: Request, out M: Response> request(data : T): Lazy<M>
}
This declaration tells you that there are different kinds of requests and responses and that there are some relations, but do not say what relations are yet.
Then I would declare the responses and requests implementations in a separate place to keep this code short and to the point
class Request1(val input: String) : Request
class Request2(val input: Double) : Request
class Response1(val output: String) : Response
class Response2(val output: Double) : Response
Then you declare the actual relations
interface Requester1: Requester<Request1, Response1>
interface Requester2: Requester<Request2, Response2>
At this point you have a file that clearly communicates the relation without any implementation details.
This is you final interface code, that solves your request for 1). document the API calls made by this Class, 2). Enforce the relationship so that Request1 can only produce Response1 ⬇️
interface Response
interface Request
interface Requester {
fun <in T: Request, out M: Response> request(data : T): Lazy<M>
}
interface Requester1: Requester<Request1, Response1>
interface Requester2: Requester<Request2, Response2>
Then you can do the implementation in a separate place to keep the interface clean and easy to understand.
sealed class Requests {
data class RequesterImpl1(val request: String) : Requests, Requester1 {
override fun request(data: Request1): Lazy<Response1> {
return lazy { Response1(data) }
}
}
data class RequesterImpl2(val request: Long) : Requests, Requester2 {
override fun request(data: Double2): Lazy<Response2> {
return lazy { Response2(data) }
}
}
}
This is the current design I am using
fun doNothing(): Unit = Unit
interface Interaction<Input, Output> {
interface Response<Output> : Interaction<Unit, Output> {
val output: Output
}
interface Request<Input, Output> : Interaction<Input, Output> {
val input: Input
fun react(output: Output): Response<Output>
}
}
sealed class Interactions<I, O> : Interaction<I, O> {
data class RequestOne(override val input: String) : Interaction.Request<String, Long> {
internal data class ResponseOne(override val output: Long) : Interaction.Response<Long>
override fun react(output: Long): Interaction.Response<Long> = ResponseOne(output)
}
data class RequestTwo(override val input: CustomInput) : Interaction.Request<CustomInput, CustomOutput> {
internal data class ResponseTwo(override val output: CustomOutput) : Interaction.Response<CustomOutput>
override fun react(output: CustomOutput): Interaction.Response<CustomOutput> = ResponseTwo(output)
}
data class RequestThree(override val input: Unit = doNothing()) : Interaction.Request<Unit, CustomOutputTwo> {
internal data class ResponseThree(override val output: CustomOutputTwo) : Interaction.Response<CustomOutputTwo>
override fun react(output: CustomOutputTwo): Interaction.Response<CustomOutputTwo> = ResponseThree(output)
}
data class RequestFour(override val input: Unit = doNothing()) : Interaction.Request<Unit, Unit> {
internal data class ResponseFour(override val output: Unit = doNothing()) : Interaction.Response<Unit>
override fun react(output: Unit): Interaction.Response<Unit> = ResponseFour()
}
data class RequestFive(override val input: CustomInputTwo) : Interaction.Request<CustomInputTwo, Unit> {
internal data class ResponseFive(override val output: Unit = doNothing()) : Interaction.Response<Unit>
override fun react(output: Unit): Interaction.Response<Unit> = ResponseFive()
}
}
I believe this approach enforces the relationships I require between individual Requests and their associated Response types.
The features of this design I would like to improve on is the use of Unit when defining the Response interface.
Also I cannot see a way to improve on the sealed class Interactions<I, O> : Interaction<I, O> {...}, as I never use the Generic I & O
I would also like to be able to define a single fun react(output: Output): Response<Output> within the parent sealed class Interactions instead of having to implement this function in each inner Action data class, however I do not think that is possible.

Kotlin generics with in produces Type mismatch when compiling

I´m working on a code with generics and when I use an in I got a TypeMismatch when compiling.
The code is the following:
open class A
class B:A()
data class DataContainer(val a:String,
val b:A)
interface Repo<T:A>{
fun setParam(param:T)
fun getParam():T
}
abstract class RepoImp<T:A>:Repo<T>{
private lateinit var parameter:T
override fun setParam(param: T) {
parameter = param
}
override fun getParam(): T {
return parameter
}
}
class BRepo:RepoImp<B>()
class Repo2(val repo: Repo<in A>){
fun process(b:DataContainer){
repo.setParam(b.b)
}
}
val repoB = BRepo()
val repo2 = Repo2(repoB)// Here I got: Type mismatch: inferred type is BRepo but Repo<in A> was expected
I also tried changing the attribute repo from Repo2 to Repo<*>
Since BRepo is a Repo<B>, it is not a Repo<in A>, (but it would satisfy Repo<out A>).
In other words, a Repo<in A> must be able to accept setParam(A()), but BRepo.setParam() can only accept a B or subclass of B.
Or to put it another way, BRepo is a Repo<B>, which is a tighter restriction on the type than Repo<A> when it comes to writing values (but looser restriction when reading values).
The reason class Repo2(val repo: Repo<*>) doesn't work is that Repo<*> is essentially a Repo<in Nothing/out A>. You can't call setParam() on a Repo<*> with any kind of object.
There's a design flaw in your code that you can't fix simply by changing Repo2's constructor signature. As it stands now, Repo2 needs to be able write A's to the object you pass to it, and a BRepo by definition does not support writing A's, only B's. You will need to make at least one of your class's definitions more flexible about types.
It might be easier to understand the covariance limitation with more common classes:
val stringList: MutableList<String> = ArrayList()
var anyList: MutableList<in Any> = ArrayList()
anyList.add(5) // ok
anyList = stringList // Compiler error.
// You wouldn't be able to call add(5) on an ArrayList<String>
Basically MutableList<String> is not a MutableList<in Any> the same way Repo<B> is not a Repo<in A>.
The Repo2 class expect to consume only type A, use Repo2<T : A>(val repo: Repo<in T>)
open class A
class B : A()
class C : A()
class D : A()
class BRepo : RepoImp<B>()
class CRepo : RepoImp<C>()
class DRepo : RepoImp<D>()
interface Repo<T : A> {
fun setParam(param: T)
fun getParam(): T
}
abstract class RepoImp<T : A> : Repo<T> {
private lateinit var parameter: T
override fun setParam(param: T) {
parameter = param
}
override fun getParam(): T {
return parameter
}
}
class Repo2<T : A>(val repo: Repo<in T>) {
fun process(b: DataContainer<T>) {
repo.setParam(b.b)
}
}
data class DataContainer<T : A>(
val a: String,
val b: T
)
fun main() {
val repoB = BRepo()
val repoC = CRepo()
val repoD = DRepo()
val repo2 = Repo2(repoB)
val repo3 = Repo2(repoC)
val repo4 = Repo2(repoD)
repo2.process(DataContainer("Process B type", B()))
repo3.process(DataContainer("Process C type", C()))
repo4.process(DataContainer("Process D type", D()))
println(repo2.repo.getParam())
println(repo3.repo.getParam())
println(repo4.repo.getParam())
}

Calling generic functions with multiple bounds?

What is the kotlin equivalent of this Java code?
private A typeA;
private B typeB;
public Test(){
typeA = createType();
typeB = createType();
}
private <T extends A & B> T createType(){
return null;
}
I tried using the kotlin converter. I am not able to call createType().
How can this be achieved ?
This is what the Kotlin equivalent looks like:
private var typeA: A? = null
private var typeB: B? = null
fun test() {
typeA = createType<C>()
typeB = createType<C>()
}
private fun <T> createType(): T? where T : A, T : B {
return null
}
open class A
interface B
class C: A(), B
Note that you can have no more than one class in where clause, the rest have to be interfaces and that when you call createType you need to provide the type parameter that satisfies the bounds (in this case extends A and implements B)
It is hard to understand the intent from your example, but here is how to express a double upper bound:
interface A
interface B
fun <T> createType():T where T : A, T : B {
return TODO()
}
But it is incompatible with your usage example:
fun test() {
val typeA: A = createType() // error
val typeB: B = createType() // error
}
How can that even work if A is not a sub type of B? Maybe there is a more realistic usage example?
Not really what you asked for, but your Java example already can be simplified to:
private <T> T createType(){
return null;
}
As your typeA and typeB are already known, that will work too.
And that can easily be transformed to the following in Kotlin:
fun <T> createType() : T = TODO("implement me")
If you give more information on why you really require T extends A & B the answers will probably get even better.

Kotlin: function delegation

I have a project that depends heavily on delegation and composition in Kotlin. Delegating properties is a breeze, but conceptually I'm not completely sure how to achieve delegation for functions in circumstances where the functions depend on other composed properties. I'd like to do something like this:
interface A {
val a: String
}
class AImpl: A {
override val a = "a"
}
interface B {
val b: String
}
class BImpl: B {
override val b = "b"
}
interface C<T> where T: A, T: B {
fun c() : String
}
class CImpl<T>(val ab: T) : C<T> where T: A, T: B {
override fun c() = ab.a + ab.b
}
// works
class ABC : A by AImpl(), B by BImpl()
// does not work
class ABC : A by AImpl(), B by BImpl(), C<ABC> by CImpl(this)
Of course, this type of thing would be achievable with the following:
interface A {
val a: String
}
class AImpl: A {
override val a = "a"
}
interface B {
val b: String
}
class BImpl: B {
override val b = "b"
}
interface C<T> where T: A, T: B {
fun c() : String
}
class CImpl<T>(val ab: T) : C<T> where T: A, T: B {
override fun c() = ab.a + ab.b
}
class AB : A by AImpl(), B by BImpl()
class ABC(ab: AB = AB(), c: C<AB> = CImpl<AB>(ab)) : A by ab, B by ab, C<AB> by c
but this feels clunky as it requires passing in objects for composition which bloats the size of the constructors - it would be cleaner for me to initialize the objects at the site of the class itself as they have no use outside of the class. Is there an elegant way to this with delegation and/or extensions?
You can make C extend A and B instead of passing to it a delegate. e.g.:
interface C : A, B {
fun c(): String
}
abstract class CImpl() : C {
abstract override val a: String
abstract override val b: String
override fun c(): String = a + b
}
class ABC : A by AImpl(), B by BImpl(), CImpl()
You can also do this with a default implementation in C without a CImpl:
interface C : A, B {
fun c(): String = a + b
}
class ABC : A by AImpl(), B by BImpl(), C
I don't think this is currently supported very well, but there's an issue that tracks this and related feature requests. (See Peter Niederwieser's comment on the issue.)

How to implement an abstract getter with property

I have java code:
public abstract class A {
abstract int getA()
}
I tried:
class B : A() {
val a = 0
}
Doesn't compile.
class B : A() {
override val a = 0
}
Still doesn't compile.
class B : A() {
override val a: Int get () = 1
}
Still doesn't compile.
class B : A() {
override val a: Int override get () = 1
}
Still doesn't compile.
class B : A() {
val a: Int override get () = 1
}
None of them are working. Does that mean I can only use
class B : A() {
override fun getA() = 1
}
? I think the last one(overriding the method) is ugly.
This could be worse when you have a getter-setter pair. It's expected to override getter-setter pair with a var property, but you have to write two methods.
According to #Miha_x64 ,
functions can be overriden only with a function.
Seems that I was trying something impossible.