Generic Kotlin factory to DRY constructor parameters - kotlin

I have the following simple class hierarchy.
abstract class B {
abstract val o : Int
}
class D1 (m: Int, n: Int) : B() {
override val o = m + n
}
class D2 (m: Int, n: Int) : B() {
override val o = m * n
}
I need a "factory function" f that gives me instances of D1 or D2 by calling it as f<D1>() or f<D2>() with hard coded parameters, say 3 and 4. The following doesn't work but illustrates what I need:
// won't compile; just demonstrates what I need
fun < T : B > f () : T {
return T(3, 4) // i. e. return T.constructor(m, n)
}
How to best accomplish this? Any DRY way is fine as long I don't have to repeat 3, 4 all over my code when I instantiate D1 or D2

The only way to do it is via reflection and reified type parameter:
inline fun <reified T : B> f(m: Int = 3, n: Int = 4): T {
val constructor = T::class.constructors.first {
it.parameters.size == 2 &&
it.parameters.all { param -> param.type == Int::class }
}
return constructor.call(m, n)
}

Here's an alternate way without reflection, but you have to manually type out a line for each class you want to handle.
inline fun <reified T : B> f(): T{
val m = 3
val n = 4
return when (T::class) {
D1::class -> D1(m, n)
D2::class -> D2(m, n)
else -> error("Unsupported type ${T::class}")
} as T
}

Related

Kotlin functions inside a const

I am learning kotlin, and want to know how to add functions to a const,
here the JS example...
function suma (a, b){
return a + b
}
console.log("sua suma::", suma(2,3))
function multiplica (a, b){
return a * b
}
console.log("sua multiplik::", multiplica(2,3))
const operations = {
suma,
multiplica
}
console.log ("sum of first class::", operations.suma(2,3))
console.log ("mult of first class::", operations.multiplica(2,3))
so how do I achieve the same on Kotlin?
Here what I have tried:
fun suma(a: Int, b: Int): Int{
return a + b
}
fun multiplica (a: Int, b: Int): Int{
return a * b
}
const operations = {
suma(),
multiplica()
}
fun main() {
println("sua suma:: ${suma(2, 3)}")
println("sua multiplica:: ${multiplica(2, 3)}")
println("sua multiplica:: ${operations.multiplica(2,3)}")
}
It can be done using object keyword, like following:
fun suma(a: Int, b: Int): Int {
return a + b
}
fun multiplica(a: Int, b: Int): Int {
return a * b
}
fun main() {
val operations = object {
val _suma = ::suma
val _multiplica = ::multiplica
}
println("sua suma:: ${operations._suma(2, 3)}")
println("sua multiplica:: ${operations._multiplica(2, 3)}")
}
The only disadvantage is that you have to choose a name for operations.XXXXX that is different from the name of referenced function: note var _suma vs fun suma. Otherwise the compiler will consider it recursive problem
"Only Primitives and String are allowed" for const
The operator you're looking for is :: (Double colon)
An enum example of this is
enum class Operations(function: KFunction<Int>) {
Suma(function = ::suma),
Multiplica(function = ::multiplica)
}
The main issues here are that Kotlin is a statically typed language, and doesn't have the same idea of Objects that can contain arbitrary attributes, like Javascript does.
I'm kinda new to Kotlin, so there may be a better way to do this, but what I'd do is define a Map to do the same sort of thing:
fun suma(a: Int, b: Int): Int{
return a + b
}
fun multiplica (a: Int, b: Int): Int{
return a * b
}
val operations: Map<String, (a: Int, b:Int) -> Int> = hashMapOf(
"suma" to ::suma,
"multiplica" to ::multiplica)
fun main() {
println("sua suma:: " + operations.get("suma")?.invoke(2, 3))
println("sua multiplica:: " + operations.get("multiplica")?.invoke(2, 3))
}
Result:
sua suma:: 5
sua multiplica:: 6
Note that operations is an immutable Map ('const' kinda) in that its contents can't be changed once it's defined.
The access and having to use invoke seems kinda messy. This seems to be due to the fact that a Map can only contain nullable types. That's the main reason I think there's probably a better way to do this.

How to explain implementation in Kotlin

I am really new in Kotlin programming language. I work with generic types and I found code statements shown below. What does it means? What is the meaning of each line?
class s(val b: t) : t by b {
fun f1(): Int = b.f3 + 1
override fun f2(g: Int): Any? = when {
g == 0 -> null
else -> b.f2(g - 1)
}
override fun l(g: Int, h: k?, z: m):
k = when {
g == 0 -> z.f1.f2.f3(1, z, true)
else -> b.l(g - 1, h, z)}}
override fun f4 (g: Int): Short = when {
g == 0 -> 0
else -> b.f4(g - 1)}}}

How to create an 'andThen' as an infix operator for composability on a generic class in Kotlin?

Problem Statement: I'm trying to recreate Scala/Finagle's andThen method chaining/composition across two types: Filters and Services.
The goal is to be able to do something like this:
val f1 = Filter1()
val f2 = Filter2()
val s3 = Service3()
val pipeline = f1 andThen f2 andThen s3
val result = pipeline(4) //execute pipeline with integer value of 4
Filters should be combinable with other filters and also a service to "end a chain". Services should also be combinable with other services. Both seem to lead to Unresolved reference andThen
Existing non-working solution:
typealias Transformer<A,B> = (A) -> B
abstract class Service<A,B>: Transformer<A,B> {
//DOESN'T WORK
infix fun <A,B,C> Service<A,B>.andThen(f: Service<B,C>): Service<A,C> {
val left = this
return object : Service<A, C>() {
override fun invoke(p1: A): C {
return f(left.invoke(p1))
}
}
}
}
typealias TwoWayTransformer<A,B,C,D> = (A, Service<C,D>) -> B
abstract class Filter<A,B,C,D>: TwoWayTransformer<A,B,C,D> {
//DOESN'T WORK
infix fun <A,B,E,F> Filter<A,B,C,D>.andThen(next: Filter<C,D,E,F>): Filter<A,B,E,F> {
val left = this
return object: Filter<A,B,E,F>() {
override fun invoke(a: A, service: Service<E,F>): B {
val s = object: Service<C,D>() {
override fun invoke(c: C): D { return next.invoke(c,service) }
}
return left.invoke(a,s)
}
}
}
//DOESN'T WORK
infix fun <A,B,C,D> Filter<A,B,C,D>.andThen(next: Service<C,D>): Service<A,B> {
val left = this
return object: Service<A,B>() {
override fun invoke(a: A): B {
return left.invoke(a, next)
}
}
}
}
Sidebar:
Filter<A,B,C,D> can stitch with Filter<C,D,E,F> which can stitch with Service<E,F> - the last two types of the left must match with the first two of the right when doing left andThen right.
A Filter<A,B,C,D> is simply a function of type: (A, Service<C,D>) -> E which simplifies further to (A, C->D) -> E
Link to working fiddle with example services/filters: https://pl.kotl.in/yIx80SzDF
The signatures you need are
infix fun <C> andThen(f: Service<B,C>): Service<A,C>
infix fun <E,F> andThen(next: Filter<C,D,E,F>): Filter<A,B,E,F>
infix fun andThen(next: Service<C,D>): Service<A,B>
Never add any type variables to functions that are already declared in the definition of the class. Never add an extra receiver for the class itself.

jetbrains exposed - select based on nullable reference column

I'm trying to select the rows from a table based on a nullable referenced column.
If you replace the reference with just a standard integer column and keep it nullable, it handles the eq just fine. I've also tried replacing the reference with optReference, but that didn't make a difference.
The error is given by the compiler.
None of the following functions can be called with the arguments supplied.
Expression<in EntityID<Int>?>.eq(Expression<in EntityID<Int>?>)   where T = EntityID<Int>?, S1 = EntityID<Int>?, S2 = EntityID<Int>? for   infix fun <T, S1 : T?, S2 : T?> Expression<in S1>.eq(other: Expression<in S2>): Op<Boolean> defined in org.jetbrains.exposed.sql.SqlExpressionBuilder
ExpressionWithColumnType<T>.eq(T)   where T cannot be inferred for   infix fun <T> ExpressionWithColumnType<T>.eq(t: T): Op<Boolean> defined in org.jetbrains.exposed.sql.SqlExpressionBuilder
ExpressionWithColumnType<EntityID<Int>>.eq(Int?)   where T = Int for   infix fun <T : Comparable<T>> ExpressionWithColumnType<EntityID<T>>.eq(t: T?): Op<Boolean> defined in org.jetbrains.exposed.sql.SqlExpressionBuilder
A basic working example showing the error given by Intellij.
object A : IntIdTable("a") {
val n = varchar("n", 255)
val x = reference("x", B).nullable()
}
object B : IntIdTable("b") {
val i = varchar("m", 255)
val y = integer("y")
}
fun main() {
connectToDatabase()
transaction {
SchemaUtils.createMissingTablesAndColumns(A, B)
A.select { A.x eq 1 }
}
}
The equivalent sql I'm want it to run is:
select * from test.a as a where a.x = 1;
A.x is not a Column<Int>, its type is actually Column<EntityID<Int>>.
It looks like you need to write the query as
A.select { A.x eq EntityID(1, B) }

Object expressions, Multiple supertype specification syntax?

I am new to Kotlin. I came across the Object Expressions section of https://kotlinlang.org
Some of the object expression syntaxes are very straight forward to understand,
Create an object of an anonymous class
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { ... }
override fun mouseEntered(e: MouseEvent) { ... }
})
Just an object
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
But I am unable to understand the "Object expression with multiple supertypes specified" example given as below:
open class A(x: Int) {
public open val y: Int = x
}
interface B { ... }
val ab: A = object : A(1), B {
override val y = 15
}
What's happening here?
${ab.y} prints 15
but syntax -> ${ab.A.y} is not valid. My understanding of ${ab.A.y} it will print 1 :)
This line here:
val ab: A = object : A(1), B {
means that the class of ab is inherited from class A and implements interface B.
Actually the code example you gave will only compile if you declare and implement the interface. This is a possible implementation:
open class A(x: Int) {
public open val y: Int = x
}
interface B {
fun hi()
}
val ab: A = object : A(1), B {
override val y = 15
override fun hi() {
println("hi")
}
}
The expression ${ab.A.y} does not make much sense in this context, because the object ab does not have any field A. A is just the inherited superclass to which you could eventually cast.
It basically creates object ab with class type A with implementation of interface B.
So, let's say your class A has some method foo() & interface B has some method bar(), you can access them both on object ab as it's of class type A with implementation of B.
Hence, here you override variable y with value 15 meaning your superclass variable y will get overridden by value 15 from 1.