Class method signature based on supplied type in Kotlin? - kotlin

I'm trying to reduce boilerplate on something I'm working on and wondering if something is possible - I suspect it's not but was looking for confirmation
class Something<T> {
private val list = mutableListOf<T>()
fun addToList(value: T) = list.add(value) }
So if I wanted to use this with a class like:
class Data(number: Int, letter: Char)
I'd have to use addToList like:
addToList(Data(1,"a"))
Is there some way to use the supplied type T to construct the method addToList dynamically? So that the class would be instantiated like:
val thing = Something<Data>()
but then addToList were called like
addToList(1,"a")
Like I said, don't think this is possible but was looking for confirmation.
What I was really trying to do was come up with something that would allow me to do this without declaring Data at all, but instead just define the structure and the subsequent addToList method when Something() was instantiated - not sure if I have described this all that well but if anyone has any suggestions in general around that I'd be grateful!
Thanks!

There are Pair and Triple tuple classes provided in the standard library which allows you to avoid declaring a class for simple combinations of values. If you need more than 3 parameters of different types, you'd need to create your own class or use a library that provides larger tuple classes. If all types are the same, you can use List instead of a tuple.
In my opinion even Triple is pushing it and anything with more than two distinct properties should just have its own data class defined.
class Something<A, B> {
private val list = mutableListOf<Pair<A, B>>()
fun addToList(valueA: A, valueB: B) = list.add(Pair(valueA, valueB))
}
val something = Something<Int, String>()
something.addToList(1, "a")
An alternate approach if you want to keep the flexibility of your Something class to hold anything would be to use an extension function.
class Something<T> {
private val list = mutableListOf<T>()
fun addToList(value: T) = list.add(value)
}
fun <A, B> Something<Pair<A, B>>.addToList(valueA: A, valueB: B) =
addToList(Pair(valueA, valueB))
val something = Something<Pair<Int, String>>()
something.addToList(1, "a")

Related

More elegant way to call getter within deeply nested data classes

I have deserialized a huge XML file and that leaves me with a lot of (nested) data classes. I'm looking for a more elegant way to do calls to specific getters within these objects. So I would rather not fill my code with all these dot calls.
I have to set quite some fields to return a new Model, which currently looks something like this (I made up the model for this question):
return TestClass(
appointmentDate = message.data.appointment.appointmentDescription.AppointmentDetails.appointmentDate
appointmentX = message.data.appointment.appointmentDescription.X.Y.Z
appointmentY = message.data.appointment.appointmentDescription.AppointmentDetails.X.Y.Z
appointmentZ = message.data.appointment.Z
)
I know I could do val appointmentDescription = message.data.appointment.appointmentDescription and do my calls from there to shorten it a bit, but there must be a shorter and better way I assume.
Does anyone know a way to do this in a more elegant and clean way? I'm pretty new to Kotlin and it is quite hard for me to properly lookup any solutions on the internet since I can't find any and am probably searching for the wrong things.
Try the with function:
data class Message (val data: Data)
data class Data (val appointment: Appointment)
data class Appointment(val appointmentDescription: AppointmentDescription)
data class AppointmentDescription(val x: Int, val appointmentDetails: AppointmentDetails)
data class AppointmentDetails(val x:Int, val y:Int)
fun TestClass(message: Message) {
with(message.data.appointment.appointmentDescription) {
val appointmentX = x
val appointmentY = appointmentDetails.y
}
}
This should be useful: https://medium.com/mobile-app-development-publication/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84

How to effectively map between Enum in Kotlin

I have two Enums,
enum class EnumKey
enum class EnumValue
and I already have a mapping from EnumKey to EnumValue.
fun EnumKey.toEnumValue(): EnumValue =
when(this) {
EnumA.KEY1 -> EnumValue.VALUE1
EnumA.KEY2 -> EnumValue.VALUE2
...
...
EnumA.KEY1000 -> EnumValue.VALUE1000
}
Now I need to have an another mapping from EnumValue to EnumKey.
Is using a Map and its reversed map created by associateBy the best way to do it? Or is there any other better ways?
Thanks!
If the enum values are somehow connected by name and they're as large as in your example, then I would advise using something like EnumValue.values().filter { it.name.contains(...) } or using regex.
If they aren't and the connection needs to be stated explicitly then I would use an object (so it's a singleton like the enums themselves) and have this mapping hidden there:
object EnumsMapping {
private val mapping = mapOf(
EnumKey.A to EnumValue.X,
EnumKey.B to EnumValue.Y,
EnumKey.C to EnumValue.Z,
)
....
and next, have the associated values available by functions in this object like:
fun getEnumValue(enumKey: EnumKey) = mapping[enumKey]
and
fun getEnumKey(enumValue: EnumValue) = mapping.filterValues { it == enumValue }.keys.single()
If it's often used or the enums are huge, and you're troubled by the performance of filtering the values every time, then you can create the association in the second way, just like you've proposed:
private val mapping2 = mapping.toList()
.associate { it.second to it.first }
and then have the second function just access this new mapping.
Writing the extension functions like you've provided, but using this object, will result in cleaner code and having the raw association still in one place.

How can i create ArrayList with Type parameter in Kotlin

Im trying to make universal class and function for different data model classes. My question is how to create ArrayList by Type parameter, type represents each time different class e.g Employee, Warehouse etc.
fun foo(type: Type){
var myList = ArrayList<type>
}
Kotlin has generics, which can be used in the following way:
fun <T> foo() {
val myList = ArrayList<T>()
}
It is important to note that you have to know the type of T at compile time. Otherwise you should probably look at reflection.

Filter out null in immutable objects list of fields

I have an immutable object:
class Foo(
val name: String,
val things: List<Thing>
)
A third party lib creates the Foo object with some 'null' Thing objects.
I am creating a new object:
val foo = thirdPartyGetFoo()
val filteredFoo = Foo(foo.name, foo.things.filterNotNull())
That works, however AndroidStudio greys out the filterNotNull function call and presents a warning:
Useless call on collection type: The inspection reports filter-like
calls on already filtered collections.
Is this the right way to filter that list? Should I ignore the warning or is there a better way?
You do not specify what library creates the object with nulls. Some deserialization libraries can use static factory methods which you could configure, and then have the factory method strip the null. For example, if this were Jackson you would simply:
class Foo(val name: String, val things: List<Thing>) {
companion object {
#JsonCreator
#JvmName("createFromNullable")
fun create(name: String, things: List<Thing?>) = Foo(name, things.filterNotNull())
fun create(name: String, things: List<Thing>) = Foo(name, things)
}
}
Then...
val goodFoo = jacksonObjectMapper().readValue<Foo>(someJsonWithNulls)
Maybe your library has options that are similar?
If not, and you don't have 100 of these things with this problem, I would probably create a temporary class to hold the results and convert that to the final class:
open class FooNullable(val name: String, open val things: List<Thing?>) {
open fun withoutNulls(): Foo = Foo(name, things.filterNotNull())
}
class Foo(name: String, override val things: List<Thing>) : FooNullable(name, things) {
override fun withoutNulls(): Foo = this
}
Then you can deserialize into FooNullable and just call withoutNulls() to get the other flavor that is clean. And if you accidentally call it on one without nulls already, it just does nothing.
val goodFoo = Foo("", emptyList<Thing>())
val alsoGoodFoo = goodFoo.withoutNulls() // NOOP does nothing
val badFoo = thirdPartyGetFoo()
val betterFoo = badFoo.withoutNulls() // clean up the instance
val safeFoo = thirdPartyGetFoo().withoutNulls() // all at once!
Not the cleanest, but does work. The downsides is this second step, although it looks like you were already planning on doing that anyway. But this model is safer than what you proposed since you KNOW which type of object you have and therefore you continue to be typesafe and have the compiler helping you avoid a mistake.
You don't have to use inheritance as in the above example, I was just trying to unify the API in case there was a reason to have either version in hand and know which is which, and also act upon them in a similar way.

Can IDEA generate componentN method in Kotlin

As http://kotlinlang.org/docs/reference/multi-declarations.html#multi-declarations says:
The component1() and component2() functions are another example of the principle of conventions widely used in Kotlin (see operators like + and *, for-loops etc.). Anything can be on the right-hand side of a destructuring declaration, as long as the required number of component functions can be called on it. And, of course, there can be component3() and component4() and so on.
For example,
class Pair<K, V>(val first: K, val second: V) {
operator fun component1(): K {
return first
}
operator fun component2(): V {
return second
}
}
But I think it's very boring to manually input these methods. So is there any way to generate these methods in IDEA.
You can let IDEA help you. Take the following example, a simple class without componentX functions:
class Ex(val a: Int, val b: Int)
And then a destructuring of it, which does not compile:
val (a,b) = Ex(1,2)
IDEA will give you some hints on how to fix the problem if you use the shortcut "Show intention action":
Try to use data classes.
In such case, you class should looks like:
data class Pair<K, V>(val first: K, val second: V)
https://kotlinlang.org/docs/reference/data-classes.html