Generic function works, but generic class doesn't? - reflection

I would like a class that is a generic for KProperty1, I can do this for a function, but not a class:
import kotlin.reflect.KProperty1
data class Dog(val name: String, val age: Int)
fun <P: KProperty1<*, *>> reflectionHelper(input: P) = input.name
fun <P: KProperty1<*, *>> getReflectionHelper(clazz: P) = ReflectionHelper<P>()
class ReflectionHelper<P: KProperty1<*, *>> {
}
fun main(args : Array<String>) {
println(reflectionHelper(Dog::age)) // Works
val helper1 = getReflectionHelper(Dog::age) // Also Works
val helper2 = ReflectionHelper<Dog::age>() // Error: Type inference failed
}

Dog::age is a value (of type KProperty1<Dog, String>), not a type. In between < and > you need to put a type, or you need to omit them entirely and the type will be inferred (that's what happens in the first two lines).
So the equivalent to your funs would be
class ReflectionHelper<P: KProperty1<*, *>>(input: P) { ... }
val helper2 = ReflectionHelper(Dog::age)
If you don't need input: P as a parameter, you'll have to specify P explicitly both for fun and for class.

Related

Kotlin: higher order function with recursion

I have to create a higher order function which returns a lambda to learn functional programming with Kotlin.
This is the class
class Product (val productName : String, val price : Double, val rating : Int) {
override fun toString () = "$productName, $price, $rating"
}
this is my function
fun productFactory (productName: String , rating : Int) : (Double) -> Product {
val x : (Double) -> Product = productFactory(productName, rating)
return x
}
this is how I call the function
val cheese = productFactory("Gouda", 5)
val product = cheese(4.99)
Although it seems to work with the needed constructors, it causes a StackOverflowError and I don't know, where the problem is. Can anybody help me?
Your function productFactory is recursively calling itself with no way to exit the recursion, so it will always cause a stack overflow.
The function it returns should certainly not be itself because the behavior is different.
You can define the returned function as a lambda:
fun productFactory (productName: String , rating : Int) : (Double) -> Product {
return { price -> Product(productName, price, rating) }
}
or use function syntax and return the function using the :: operator:
fun productFactory (productName: String , rating : Int) : (Double) -> Product {
fun produce(price: Double) = Product(productName, price, rating)
return ::produce
}

Using multiple constructors for R classes and subclasses

I would like to use multiple constructors in my R S4 class.
I have an object that has three slots. To make that object, sometimes I want to just give the values for the three slots outright. But sometimes I'd like to provide a matrix, and I have a function that can take a matrix and return what those three slots should be.
At first, it seems like I could write a function as a constructor. So I could write objectFromMatrix(matrix) --> object with three slots. The problem is that I also have sub-classes that inherit from that main class, and I want to be able to use that constructor with them as well.
So I could just write functions as extra constructors for each of the subclasses, but that would be a bit tedious and not super OO-like.
To make my problem a little more tangible, I'll try to write a minimal example below. I'll write it in Java, but I'm a bit rusty so let me know if it doesn't make sense.
Desired structure, in Java:
// An abode is a place where you live and it has a size
class Abode {
int size = 1;
// Main constructor that just assigns args to fields
Abode(int size) {
this.size = size;
}
// Alternative constructor that takes in a different datatype
// and computes args to assign to fields
Abode(string description) {
if(description eq "Large") {
this.size = 5;
}
if(description eq "Small") {
this.size = 1;
}
}
// To keep it simple, a house is just an abode with a name
class House extends Abode {
String name;
House(int size, String name) {
super(size);
this.name = name;
}
House(string size, String name) {
super(size);
this.name = name;
}
}
This implementation works nicely because I can call Abode("big") or House("big", "Casa de me"), and both of those get passed to the extra constructor I built in the Abode class.
Keeping up with the house analogy, this is the best I've been able to do in R:
# An abode is a place you live and it has a size
setClass("Abode",
slots =
list(size = "numeric")
)
# Alternative constructor that takes in a different datatype
# and computes args to assign to fields
abode_constructor_2 <- function(sizeString) {
if (sizeString == "big") {return new("Abode", size = 5)}
if (sizeString == "small") {return new("Abode", size = 1)}
}
# A house is an abode with a name
setClass("House",
slots =
list(name = "string"),
contains = "Abode"
)
# I already defined this constructor but I have to do it again
house_constructor_2 <- function(sizeString, name) {
if (sizeString == "big") {return new("House", size = 5, name = name)}
if (sizeString == "small") {return new("House", size = 1, name = name)}
}
In case it helps, here is a minimal example of the real context where this problem is coming up. I define an extra constructor for the Sensor class, sensor_constructor_2, as a function. But then, when I have a class that inherits from Sensor, I have to make that constructor over again.
# A sensor has three parameters
setClass("Sensor",
slots =
list(Rmin = "numeric", Rmax = "numeric", delta = "numeric")
)
# I also like to make sensors from a matrix
sensor_constructor_2 <- function(matrix) {
params <- matrix_to_params(matrix)
return (new("Sensor", Rmin = params[1], Rmax = params[2], delta = params[3]))
}
# A redoxSensor is just a sensor with an extra field
setClass("redoxSensor",
slots =
list(e0 = "numeric"),
contains = "Sensor"
)
# Goal: make this extra constructor unnecessary by making sensor_constructor_2 a property of the sensor class
extraConstructor_redox <- function(matrix, e0) {
params <- matrix_to_params(matrix)
return (new("redoxSensor", Rmin = params[1], Rmax = params[2], delta = params[3]), e0 = e0)
}
There is no reason why you can't do this with one S4 constructor by using default arguments and a little extra logic, along the lines of
setClass("Abode",
slots = list(size = "numeric")
) -> Abode
setClass("House",
slots = list(name = "character"),
contains = "Abode"
) -> House
createDwelling <- function(size=0,name,sizeString){
if(!missing(sizeString)){
if(sizeString == "Large") size <- 5
else if(sizeString == "Small") size <- 1
else stop("invalid sizeString")
}
if(missing(name)) return(Abode(size=size))
else return(House(size=size,name=name))
}
example usage:
> createDwelling(size=3)
An object of class "Abode"
Slot "size":
[1] 3
> createDwelling(sizeString="Small")
An object of class "Abode"
Slot "size":
[1] 1
> createDwelling(sizeString="Small",name="my house")
An object of class "House"
Slot "name":
[1] "my house"
Slot "size":
[1] 1

Can I convert a Kotlin KFunction1 to a KFunction0 by applying the argument?

I have a reference to a functionthat needs a parameter.
fun foo(x: Int) = 2 * x
val f: KFunction1<Int, Int> = ::foo
Is there any way to write applyArgument where
val f2: KFunction0<Int> = f1.applyArgument(42)
assertEquals("foo", f2.name)
assertEquals(84, f2())
I don't want to use a callable reference, as I need access to the name property.
hope it helps you:
fun foo(x: Int) = 2 * x
val f1 = ::foo
val f0 = { -> f1(42) }
f0() //84
KFunctions are intented to represent functions that are explicitly decleared in Kotlin code, but f2 is not declared anywhere in the code. In addition KFunction has lot of reflection properties and functions which are not relevant to the applied function f2. Therefore even if it is possible it is not recommended.
If you want to do it anyway you can simply write an applyArgument function in this way:
fun <T, R> KFunction1<T, R>.applyArgument(value: T): KFunction0<R> {
return object : KFunction<R> by this, KFunction0<R> {
override fun invoke(): R {
return this#applyArgument(value)
}
}
}
But, if what you need is to preserve the name, I would do it in a safe way. One way could be:
data class Named<out T>(val name: String, val value: T)
fun <T, R> Named<T>.map(transform: (T) -> R): Named<R> = Named(name, transform(value))
val <F : KFunction<*>> F.named: Named<F>
get() = Named(name, this)
Then use it:
fun foo(x: Int) = 2 * x
val f: Named<(Int) -> Int> = ::foo.named
val f2: Named<() -> Int> = f.map { fValue -> { fValue(42) } }
assertEquals("foo", f2.name)
assertEquals(84, f2.value())
Partial application is possible.
You may just declare a function for partial application and use it for the :: reference.
Hence, the name would not be the original function. Another approach - create your own classes/interfaces
data class MyFunction1<T, R>(val name: String, val f: (T) -> R) {
operator fun invoke(t: T) = f(t)
}
data class MyFunction0<R>(val name: String, val f: () -> R) {
operator fun invoke() = f()
}
Now define the curring:
fun MyFunction1<T, R>.curry(t: T) = MyFunction0(name){ f(t) }
(it can be a member function too)

Kotlin's reduce() function with different types

I was looking through array extension functions and found reduce() one
inline fun <S, T: S> Array<out T>.reduce(operation: (acc: S, T) -> S): S {
if (isEmpty())
throw UnsupportedOperationException("Empty array can't be reduced.")
var accumulator: S = this[0]
for (index in 1..lastIndex) {
accumulator = operation(accumulator, this[index])
}
return accumulator
}
here the accumulator variable of type S assigned with first element from the array with type T.
Can't wrap my head around the real use case of reduce() function with two data types. Here synthetic example which actually doesn't make any sense.
open class A(var width: Int = 0)
class B(width: Int) : A(width)
val array = arrayOf(A(7), A(4), A(1), A(4), A(3))
val res = array.reduce { acc, s -> B(acc.width + s.width) }
Seems most real life use cases with this function use this signature:
inline fun <T> Array<out T>.reduce(operation: (acc: T, T) -> T): T
Can you help with providing some examples, where reduce() function can be useful with different types.
Here is an example:
interface Expr {
val value: Int
}
class Single(override val value: Int): Expr
class Sum(val a: Expr, val b: Expr): Expr {
override val value: Int
get() = a.value + b.value
}
fun main(args: Array<String>) {
val arr = arrayOf(Single(1), Single(2), Single(3));
val result = arr.reduce<Expr, Single> { a, b -> Sum(a, b) }
println(result.value)
}

How to reverse a Map in Kotlin?

I am trying to reverse a Map in Kotlin. So far, I have come up with:
mapOf("foo" to 42)
.toList()
.map { (k, v) -> v to k }
.toMap()
Is there any better way of doing this without using a middleman(middlelist)?
Since the Map consists of Entrys and it is not Iterable you can use Map#entries instead. It will be mapped to Map#entrySet to create a backed view of Set<Entry>, for example:
val reversed = map.entries.associateBy({ it.value }) { it.key }
OR use Iterable#associate, which will create additional Pairs.
val reversed = map.entries.associate{(k,v)-> v to k}
OR using Map#forEach:
val reversed = mutableMapOf<Int, String>().also {
// v-- use `forEach` here
map.forEach { (k, v) -> it.put(v, k) }
}.toMap()
// ^--- you can add `toMap()` to create an immutable Map.
Here is a simple extension function that reverse a map - without generating unneeded garbage (like pairs, intermediate data structures and unnecessary closures )
fun <K, V> Map<K, V>.reversed() = HashMap<V, K>().also { newMap ->
entries.forEach { newMap.put(it.value, it.key) }
}
note that apply is inlined, and entries.forEach is also inlined (which is not the same for Map::forEach)
In case your map is not a 1-1 mapping and you want the inversion to be a list of values:
mapOf(1 to "AAA", 2 to "BBB", 3 to "BBB").toList()
.groupBy { pair -> pair.second } // Pair<Int, String>
.mapValues { entry ->
entry.value.map { it.first } // Entry<String, List<Pair<Int, String>>
}
If you need to reverse a multimap like m: Map<K, List<V>> to a Map<V, List<K>> you can do
m
.flatMap { it.value.map { oneValue -> oneValue to it.key } }
.groupBy({ it.first }, { it.second })
.toMap()
In sequence,
mapOf('a' to listOf('b', 'c'), 'd' to listOf('b'))
gets flat mapped to a sequence like
listOf('b' to 'a', 'c' to 'a', 'b' to 'd') which gets grouped to
listOf('b' to listOf('a', 'd'), 'c' to listOf('a')) which then gets converted to a map.
This probably creates intermediate objects.
I'm still learning the ins and outs of Kotlin, but I had the same requirement and as of Kotlin 1.2 it appears that you can iterate over a Map and so map() it directly like this:
#Test
fun testThatReverseIsInverseOfMap() {
val intMap = mapOf(1 to "one", 2 to "two", 3 to "three")
val revMap = intMap.map{(k,v) -> v to k}.toMap()
assertTrue(intMap.keys.toTypedArray() contentEquals revMap.values.toTypedArray())
assertTrue(intMap.values.toTypedArray() contentEquals revMap.keys.toTypedArray())
}
This is my take on a 1:1 map
private fun <K, V> Map<K, V>.reverseOneToOneMap(): Map<V, K> {
val result = this.entries.associateBy({ it.value }) { it.key }
if (result.size != this.size) {
throw RuntimeException("Map must be 1:1")
}
return result
}

Resources