How to pass object as argument in Kotlin - kotlin

I have these two objects A and B I want to use these objects interchangeably in the digit class like shown in this snippet code
internal object A {
internal const val ZERO = "ZERO"
internal const val ONE = "ONE"
}
internal object B {
internal const val ZERO = "ZERO"
internal const val ONE = "UN"
}
class Digit(Lang: String) {
private var X: Any? = null
init {
when (Lang) {
"eng" -> X = A
"fr" -> X = B
}
}
fun spell() {
println(X.ZERO)
}
}
I want inside the Digit class to use both objects, not at the same time, only when I want the English language the Digit class use object A and when I want french language the Digit class use the object B.
I should use reflection? or is there a better design?

The simplest answer is to have your objects all implement the same interface, e.g.:
interface Language {
val ZERO: String
val ONE: String
}
internal object A: Language {
override val ZERO = "ZERO"
override val ONE = "ONE"
}
// …
You can then set a Language reference to any object implementing that interface.
A related (and more concise) approach might be to use an enum:
enum class Language(val ZERO: String, val ONE: String) {
A("ZERO", "ONE"), B("ZERO", "UN")
}
You can then refer to the objects as Language.A &c.
But in practice, none of these approaches scale well. You're likely to end up with a good number of language strings, and probably quite a few languages to support, and those methods will get long-winded. And hard-coding all the strings will make it much more awkward to manage.
So it's more usual to store all the language strings in resource files and load them in at runtime. You could do that manually, e.g. storing the strings in a map — but many platforms and frameworks support standard ways to select the right language, load the strings, and use them. There are many existing questions about this.

data class Translation(val ZERO: String, val ONE: String)
val a = Translation(ZERO = "ZERO", ONE = "ONE")
val b = Translation(ZERO = "ZERO", ONE = "UN")
class Digit(Lang: Translation) {
private val x = Lang
fun spell() {
println(x.ONE)
}
}
Digit(a).spell()
Digit(b).spell()

Related

Kotlin — creating new instance with copy() does not prevent methods called on copied instance from modifying original instance [duplicate]

Could someone explain how exactly the copy method for Kotlin data classes work? It seems like for some members, a (deep) copy is not actually created and the references are still to the original.
fun test() {
val bar = Bar(0)
val foo = Foo(5, bar, mutableListOf(1, 2, 3))
println("foo : $foo")
val barCopy = bar.copy()
val fooCopy = foo.copy()
foo.a = 10
bar.x = 2
foo.list.add(4)
println("foo : $foo")
println("fooCopy: $fooCopy")
println("barCopy: $barCopy")
}
data class Foo(var a: Int,
val bar: Bar,
val list: MutableList<Int> = mutableListOf())
data class Bar(var x: Int = 0)
Output:
foo : Foo(a=5, bar=Bar(x=0), list=[1, 2, 3])
foo : Foo(a=10, bar=Bar(x=2), list=[1, 2, 3, 4])
fooCopy: Foo(a=5, bar=Bar(x=2), list=[1, 2, 3, 4])
barCopy: Bar(x=0)
Why is barCopy.x=0 (expected), but fooCopy.bar.x=2 (I would think it would be 0). Since Bar is also a data class, I would expect foo.bar to also be a copy when foo.copy() is executed.
To deep copy all members, I can do something like this:
val fooCopy = foo.copy(bar = foo.bar.copy(), list = foo.list.toMutableList())
fooCopy: Foo(a=5, bar=Bar(x=0), list=[1, 2, 3])
But am I missing something or is there a better way to do this without needing to specify that these members need to force a deep copy?
The copy method of Kotlin is not supposed to be a deep copy at all. As explained in the reference doc (https://kotlinlang.org/docs/reference/data-classes.html), for a class such as:
data class User(val name: String = "", val age: Int = 0)
the copy implementation would be:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
So as you can see, it's a shallow copy. The implementations of copy in your specific cases would be:
fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list) = Foo(a, bar, list)
fun copy(x: Int = this.x) = Bar(x)
Beware of those answers who are just copying list reference from an old object into the new one. One quick way (not very efficient, though) of deep copying is to serialize/deserialize objects i.e. convert the objects into JSON and then transform them back to POJO.
If you are using GSON, here is a quick piece of code:
class Foo {
fun deepCopy() : Foo {
return Gson().fromJson(Gson().toJson(this), this.javaClass)
}
}
As #Ekeko said, the default copy() function implemented for data class is a shallow copy which looks like this:
fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list)
To perform a deep copy, you have to override the copy() function.
fun copy(a: Int = this.a, bar: Bar = this.bar.copy(), list: MutableList<Int> = this.list.toList()) = Foo(a, bar, list)
There is a way to make a deep copy of an object in Kotlin (and Java): serialize it to memory and then deserialize it back to a new object. This will only work if all the data contained in the object are either primitives or implement the Serializable interface
Here is an explanation with sample Kotlin code https://rosettacode.org/wiki/Deepcopy#Kotlin
import java.io.Serializable
import java.io.ByteArrayOutputStream
import java.io.ByteArrayInputStream
import java.io.ObjectOutputStream
import java.io.ObjectInputStream
fun <T : Serializable> deepCopy(obj: T?): T? {
if (obj == null) return null
val baos = ByteArrayOutputStream()
val oos = ObjectOutputStream(baos)
oos.writeObject(obj)
oos.close()
val bais = ByteArrayInputStream(baos.toByteArray())
val ois = ObjectInputStream(bais)
#Suppress("unchecked_cast")
return ois.readObject() as T
}
Note: This solution should also be applicable in Android using the Parcelable interface instead of the Serializable. Parcelable is more efficient.
Building on a previous answer, an easy if somewhat inelegant solution is to use the kotlinx.serialization facility. Add the plugin to build.gradle as per the docs, then to make a deep copy of an object, annotate it with #Serializable and add a copy method which converts the object to a serialised binary form, then back again. The new object will not reference any objects in the original.
import kotlinx.serialization.Serializable
import kotlinx.serialization.cbor.Cbor
#Serializable
data class DataClass(val yourData: Whatever, val yourList: List<Stuff>) {
var moreStuff: Map<String, String> = mapOf()
fun copy(): DataClass {
return Cbor.load(serializer(), Cbor.dump(serializer(), this))
}
This won't be as fast as a handwritten copy function, but it does not require updating if the object is changed, so is more robust.
I face the same problem. Because in kotlin, ArrayList.map {it.copy} not copying all items of an object specially if a member is list of another object inside this.
The only solution, for deep copying of all items of an object I found on the web, is to serialize and deserialize the object when you send or assign it to a new variable. Code like as follows.
#Parcelize
data class Flights(
// data with different types including the list
) : Parcelable
Before I receiving List of Flights, We can use JSON to deserialize the Object and serialize the object same time!!!.
First, we create two extension functions.
// deserialize method
fun flightListToString(list: ArrayList<Flights>): String {
val type = object : TypeToken<ArrayList<Flights>>() {}.type
return Gson().toJson(list, type)
}
// serialize method
fun toFlightList(string: String): List<Flights>? {
val itemType = object : TypeToken<ArrayList<Flights>>() {}.type
return Gson().fromJson<ArrayList<Flights>>(string, itemType)
}
We can use it like below.
// here I assign list from Navigation args
private lateinit var originalFlightList: List<Flights>
...
val temporaryList = ArrayList(makeProposalFragmentArgs.selectedFlightList.asList())
originalFlightList = toFlightList(flightListToString(temporaryList))!!
Later, I send this list to Recycler Adapter & there the content of the Flights object would be modified.
bindingView.imageViewReset.setOnClickListener {
val temporaryList = ArrayList(makeProposalFragmentArgs.selectedFlightList.asList())
val flightList = toFlightList(flightListToString(temporaryList))!!
**adapter**.resetListToOriginal(flightList)
}
Maybe you can use kotlin reflection in some way here, this example is not recursive but should give the idea:
fun DataType.deepCopy() : DataType {
val copy = DataType()
for (m in this::class.members) {
if (m is KProperty && m is KMutableProperty) {
m.setter.call(copy, if (m.returnType::class.isData) {
(m.getter.call(this) to m.returnType).copy()
} else m.setter.call(copy, m.getter.call(this)))
}
}
return copy
}
If you use Jackson and not concerned about performance,then this simple extension function will give you this feature.
private val objectMapper = ObjectMapper()
.registerModule(KotlinModule())
.registerModule(JavaTimeModule())
fun <T> Any.copyDeep(): T {
return objectMapper.readValue(objectMapper.writeValueAsString(this), this.javaClass) as T
}
Use this function:
private val gson = Gson()
fun <T> deepCopy(item: T?, clazz: Class<T>): T {
val str = gson.toJson(item)
return gson.fromJson(str, clazz)
}
What you want is a deep copy. There are many tools available to do this.
MapStruct: https://mapstruct.org/
Mapstruct generates code at compile time. Normally, it is to auto-generate mappers between java objects, but it also has a 'clone' functionality to create a deep copy of an object. Since this is generated code of what you'd manually write, it is the fastest way to achieve this.
There are many more (kryo, dozer, etc...), you can actually just google, for example here: https://programmer.group/performance-comparison-between-shallow-and-deep-copies.html
DO AVOID serialization-based 'clone': apache commons' SerializationUtils, jackson, gson, etc... They have a huge overhead, since it first creates a middle state. They are about 10-100 times slower than actual copying.

How to pass a variable from main function to another function and modify it? (Kotlin)

I am aware that an argument passed to a function will be seen as "val", even if the variable was initialized as "var". But this has been a problem for me. In this example code below, I want to modify the value of variable "num" by using the function "changeNum". But of course, Kotlin won't allow me to modify it. How do I get around this? How can I use the function "changeNum" to modify the variable "num"?
fun main() {
var num: Int = 5
changeNum(num)
}
fun changeNum(num: Int){
num += 2
print(num)
}
Kotlin is pass-by-value, so you can't do that directly with primitive types like Int.
The usual approach is to just return a new value instead of modifying what you receive as argument (a functional approach). It makes it clearer from the calling code's perspective:
fun main() {
var num: Int = 5
num = changeNum(num)
}
fun changeNum(num: Int): Int {
val newValue = num + 2
print(newValue)
return newValue
}
If you really want to mutate the variable instead of returning a new value, here are 2 approaches I'm thinking of to do this:
put all the code operating on this value into a class, and make the local variable a property of that class (this is the OO approach)
put this primitive variable into a class, and pass an instance of that class
Option 1 would look like this:
class SomeClass(var num: Int) {
fun changeNum() {
num += 2
print(num)
}
}
fun main() {
val container = SomeClass(5)
container.changeNum()
}
Option 2 would look like this:
class SomeMutableContainer(var num: Int)
fun main() {
val container = SomeMutableContainer(5)
changeNum(container)
}
fun changeNum(container: SomeMutableContainer) {
container.num += 2
print(container.num)
}
It's possible to do this in Kotlin with a property
import kotlin.reflect.KMutableProperty0
var num = 1
fun main() {
println(num)
changeNum(::num)
println(num)
}
fun changeNum(numProperty: KMutableProperty0<Int>) {
numProperty.set(12345)
}
>> 1
>> 12345
A KMutableProperty0 represents a basic var, so you can pass in a property reference using the ::num syntax (same as how you'd pass a function reference). That way, instead of passing the current value, you're providing the function with a reference to the property itself, and then you can call set on it.
But the question is, do you really want to do this? Or are you overcomplicating something that should be done in a more simple way, or a more readable one? You can't actually do this with a variable, like you're trying to do inside fun main(), only properties on an object (top-level vars, basically) - but even if you could, why wouldn't you just do this instead?
fun main() {
var num: Int = 5
...
num = changeNum(num) // this would need renaming but y'know
}
it's still a one-line call, your changeNum function can still have side effects, do validation etc, it just returns the result instead of setting it as a side effect. This is a lot easier to follow, especially when it's the usual way of setting a value on a thing.
If you really want to use references, but making them top-level in your class is messy, then maybe consider creating a state object instead:
import kotlin.reflect.KMutableProperty0
data class AllThemNums(var num1 :Int = 1, var num2: Int = 9999)
fun main() {
val nums = AllThemNums(num1 = 5)
changeNum(nums::num1)
println(nums)
}
fun changeNum(numProperty: KMutableProperty0<Int>) {
numProperty.set(numProperty.get() + 2)
}
>> AllThemNums(num1=7, num2=9999)
you could even put the changeNum function inside the data class!
Im my project, I've defined a generic type for enclosing all scalar types, both primitives and user-defined.
data class pTp<T>(var v: T)
So I can create
fun PercAcumNorm(percAcum:pTp<Double>, perc:pTp<Double>,
valor:Double, Soma:Double)
{
perc.v = valor/soma
parcAcum.v += perc.v
}
Then one just needs to call
....
var pAcum:pTp<Double> = pTp(0.40)
var p = 0
var valor = 5
var soma = 100
percCalc(pAcum, p, soma, valor)
println(pAcum.v) // it prints 0.45
It's not the cleanest solution, but it's what can be done without using Kotlin's built-in features, which may be modified in the future.

Kotlin Generics - It is possible get integer position of an element of whatever type passed like ordinals method does for Enum defined classes?

There's an already built in way that fulfill my request?
I know Set are unordered
I need to do a vector based Set.
I need to know the position of any value of a generic type to place them in the corresponding index of the array, So I can avoid duplications of the elements.
I'm not ordering or defining an order of the Set.
I don't have any operators that missbehave or break any Set Costraint
Please note that I know this implementation is not efficient for any types that seems infinite like Integers.
I need to do it for an educational purpose.
I have already implemented List Ordered and Hash Table based ones.
For now I have this class, that works flawlessy:
package ads
class MySet<E : Enum<E>> {
//More details for clarify
private val maxSet = 127
private var myset = arrayOfNulls<Boolean>(maxSet)
private fun getOrdinal(eelement : E) : Int{
return eelement.ordinal
}
/*
more set operators that needs of getOrdinal
*/
fun insert(xelement: E){
myset[getOrdinal(xelement)] = true
}
}
import ads.MySet as RawSet
enum class MyColors{
Red,
Green,
Blue,
Yellow,
Black,
Mint;
}
fun main() {
val myfavc = RawSet<MyColors>()
val yourfavc = RawSet<MyColors>()
//Following operations...
myfavc.insert(MyColors.Red)
yourfavc.insert(MyColors.Blue)
}
I need now to make another class in the same way but working with whatever abstract type already defined in kotlin.
package ads
class MySet<T> {
//More details for clarify
private val maxSet = 127
private var myset = arrayOfNulls<Boolean>(maxSet)
private fun getOrdinal(telement : T) : Int{
/*
For any abstract type return the order of any element
checks if the integer is not greater than maxSet otherwhise it
throws an Exception or manages this istance in other way
*/
}
/*
more set operators that needs of getOrdinal
*/
fun insert(xelement: T){
myset[getOrdinal(xelement)] = true
}
}
import ads.MySet as RawSeT
//Istance using Int
fun main() {
val myfav = RawSet<Int>()
val yourfav = RawSet<Int>()
//Following operations...
myfav.insert(11)
yourfav.insert(123)
}
I guess there's no built-in way to do so in a generic way.
but I'm still learning kotlin, so maybe I'm missing something useful.
I'm not asking to do my paper.
I don't need a full alternative solutions that I should find out by myself but
I'm opened to read about any tips or resources that can help me to clarify how abstract types works in Kotlin(or Programming Languages) infos like :
How are ordered.
If any value of any type can be compared based on their position
(like c > a for chars).
Range of values/Max values represented for any "apparently
infinite" type like Integers.
Thanks you!
P.S. = Please consider that I'm not an english native, be patient!
Enums are implicitly ordered in declaration order and amount of instances of each enum is finite, so they could be ordered globally and their ordinal could be represented as Int.
Ints (as well as Bytes and Chars) are naturally ordered and have ranges (Int.MIN_VALUE..Int.MAX_VALUE, etc.), so each of them could have an ordinal represented as Int too.
All types implementing Comparable interface could be compared in pairs and any subset of their instances could be ordered, but it doesn't mean that each of them have some global Int ordinal among all possible instances, because set of Ints is finite (2^32 items), and set of all unique instances of generic type T could be countably infinite (like BigInteger) or even uncountable (like Double) (see wiki about cardinality).
All other types couldn't be even compared in pairs (without respectful Comparator<T>).
So you need to manually limit instances of each T that are about to be added in your set and either maually order them or provide respectful Comparator<T> to construct a Map<T, Int> which you'll need to use for subsequent ordinal evaluation:
class SetOfSomehowOrderedInstancesOfType<T>(private val order: Map<T, Int>) {
private val maxSet = order.size
private var myset = BooleanArray(order.size)
private fun getOrdinal(eelement: T): Int {
return order[eelement] ?: throw RuntimeException("Order unknown")
}
fun insert(xelement: T) {
myset[getOrdinal(xelement)] = true
}
}
Usage:
fun main() {
val myFavouriteRealNumbersInMyFavouriteOrder =
listOf(99.2123, -2355.12, 1.1, 3.14, 100.0, 123214214215.123331322145)
val myfavc = SetOfSomehowOrderedInstancesOfType<Double>(myFavouriteRealNumbersInMyFavouriteOrder.mapToIndex())
myfavc.insert(99.2123) //will be inserted with ordinal = 0
val myFavouriteRealNumbersInNaturalOrder = myFavouriteRealNumbersInMyFavouriteOrder.sorted()
val yourfavc = SetOfSomehowOrderedInstancesOfType<Double>(myFavouriteRealNumbersInNaturalOrder.mapToIndex())
yourfavc.insert(99.2123) //will be inserted with ordinal = 3
}
Alternatively you may define Orderable and Ordinator<T> interfaces (similar to Comparable<T> and Comparator<T>) and determine ordinal using them:
fun interface Ordinator<T> {
fun getOrderOf(x : T) : Int
}
interface Orderable {
val order : Int
}
class MySet<T>(private val ordinator: Ordinator<T>? = null) {
private val maxSet = 127
private var myset = BooleanArray(maxSet)
private fun getOrdinal(eelement: T) = when {
eelement is Orderable -> eelement.order
ordinator != null -> ordinator.getOrderOf(eelement)
else -> throw RuntimeException()
}
fun insert(xelement: T) {
myset[getOrdinal(xelement)] = true
}
}
Also you may define auxilary function, generalizing previous approach:
fun <T> ordinatorOf(order: List<T>) = object : Ordinator<T> {
private val order = order.mapToIndex()
override fun getOrderOf(x: T) = this.order[x] ?: throw RuntimeException()
}
Usage:
val stringsOrderedByTheirLength = MySet<String> { it.length }
stringsOrderedByTheirLength.insert("aaa") //will be inserted with ordinal = 3
val myFavouriteRealNumbersInMyFavouriteOrder =
listOf(99.2123, -2355.12, 1.1, 3.14, 100.0, 123214214215.123331322145)
val myfavc = MySet(ordinatorOf(myFavouriteRealNumbersInMyFavouriteOrder))
myfavc.insert(99.2123) //will be inserted with ordinal = 0
As somebody pointed out to me that some abstract types representing for an istance Real Numbers can't be done so easily.
The implementation with the enum class works flawlessy but it's been refused from my university professor because I need to use the same syntax for every implementation of the same Data Structure.
Other implementation I have
- HashTableSet<T>
- OrderedListSet<T>
they ask only for an abstract type that can be whatever type, they will work without problem.
I need to do it the same with the
ArraySet<E : Enum<E>>
So if this can't be done easily with Generics, directly...
I'm thinking about mixing them.
Like whatever T type I have
it creates an object called "Domain" so whatever element it insert, before placing them in the array of the set, it place them inside there in a specific order so it simulates what enum it was doing.
I guess that Enumerations can't be defined during the runtime, dinamically.
Then probably I have to define Domain<T> as a private class/object(not sure) that :
Collect the element of the istance of ArraySet(above MySet) inserts with its opeator .insert()
It orders the element comparing to the ones that are already inside
Once is ordered delete all the duples
Re-arrange the whole Boolean Array everytime insert is used based on how Domain grows. (or find out a different algo that partially re-arrange the boolean array)
What do you think?
Advice me more, thanks.

Generic inline function

Let's say I have an object which helps me to deserialize other objects from storage:
val books: MutableList<Book> = deserializer.getBookList()
val persons: MutableList<Person> = deserializer.getPersonList()
The methods getBookList and getPersonList are extension functions I have written. Their logic is allmost the same so I thought I may can combine them into one method. My problem is the generic return type. The methods look like this:
fun DataInput.getBookList(): MutableList<Book> {
val list = mutableListOf<Book>()
val size = this.readInt()
for(i in 0 .. size) {
val item = Book()
item.readExternal(this)
list.add(item)
}
return list
}
Is there some Kotlin magic (maybe with inline functions) which I can use to detect the List type and generify this methods? I think the problem would be val item = T() which will not work for generic types, right? Or is this possible with inline functions?
You cannot call the constructor of a generic type, because the compiler can't guarantee that it has a constructor (the type could be from an interface). What you can do to get around this though, is to pass a "creator"-function as a parameter to your function. Like this:
fun <T> DataInput.getList(createT: () -> T): MutableList<T> {
val list = mutableListOf<T>()
val size = this.readInt()
for(i in 0 .. size) {
val item = createT()
/* Unless readExternal is an extension on Any, this function
* either needs to be passed as a parameter as well,
* or you need add an upper bound to your type parameter
* with <T : SomeInterfaceWithReadExternal>
*/
item.readExternal(this)
list.add(item)
}
return list
}
Now you can call the function like this:
val books: MutableList<Book> = deserializer.getList(::Book)
val persons: MutableList<Person> = deserializer.getList(::Person)
Note:
As marstran mentioned in a comment, this requires the class to have a zero-arg constructor to work, or it will throw an exception at runtime. The compiler will not warn you if the constructor doesn't exist, so if you pick this way, make sure you actually pass a class with a zero-arg constructor.
You can't initialize generic types, in Kotlin or Java. At least not in the "traditional" way. You can't do this:
val item = T()
In Java, you'd pass a Class<T> and get the constructor. Very basic example of that:
public <T> void x(Class<T> cls){
cls.getConstructor().newInstance(); // Obviously you'd do something with the return value, but this is just a dummy example
}
You could do the same in Kotlin, but Kotlin has a reified keyword that makes it slightly easier. This requires an inline function, which means you'd change your function to:
inline fun <reified T> DataInput.getBookList(): MutableList<T> { // Notice the `<reified T>`
val list = mutableListOf<T>() // Use T here
val size = this.readInt()
for(i in 0 .. size) {
// This is where the initialization happens; you get the constructor, and create a new instance.
// Also works with arguments, if you have any, but you used an empty one so I assume yours is empty
val item = T::class.java.getConstructor().newInstance()!!
item.readExternal(this) // However, this is tricky. See my notes below this code block
list.add(item)
}
return list
}
However, readExternal isn't present in Any, which will present problems. The only exception is if you have an extension function for either Any or a generic type with that name and input.
If it's specific to some classes, then you can't do it like this, unless you have a shared parent. For an instance:
class Book(){
fun readExternal(input: DataInput) { /*Foo bar */}
}
class Person(){
fun readExternal(input: DataInput) { /*Foo bar */}
}
Would not work. There's no shared parent except Any, and Any doesn't have readExternal. The method is manually defined in each of them.
You could create a shared parent, as an interface or abstract class (assuming there isn't one already), and use <reified T : TheSharedParent>, and you would have access to it.
You could of course use reflection, but it's slightly harder, and adds some exceptions you need to handle. I don't recommend doing this; I'd personally use a superclass.
inline fun <reified T> DataInput.getBookList(): MutableList<T> {
val list = mutableListOf<T>()
val size = this.readInt()
val method = try {
T::class.java.getMethod("readExternal", DataInput::class.java)
}catch(e: NoSuchMethodException){
throw RuntimeException()
}catch(e: SecurityException){
throw RuntimeException()// This could be done better; but error handling is up to you, so I'm just making a basic example
// The catch clauses are pretty self-explanatory; if something happens when trying to get the method itself,
// These two catch them
}
for(i in 0 .. size) {
val item: T = T::class.java.getConstructor().newInstance()!!
method.invoke(item, this)
list.add(item)
}
return list
}

Kotlin equivalent of Optional.map and a method reference

The Java
Consider the following Java:
private void example() {
Optional<String> foo = ...
Optional<String> bar =
foo.map(this::transform1)
.map(this::transform2)
}
private String transform1(String s) {
return s + "!";
}
private String transform2(String s) {
return "#" + s;
}
Note that the transform methods accept non-Optional values.
Question
Does Kotlin have a built-in mechanism to achieve the same thing when using its nullable/non-nullabe types?
The first attempt
I managed to achieve this effect with the following:
fun <A, B> nullMap(a: A?, mapper: (a: A) -> B?): B? =
if (a != null) mapper.invoke(a) else null
fun example() {
val foo: String? = "Space cookies"
val bar1: String? = nullMap(foo, Example::transform1)
val bar2: String? = nullMap(bar1, Example::transform2)
}
fun transform(s: String) = s + "!"
fun transform2(s: String) = "#" + s
(Again, we note that for the transform methods, s is a non-nullable String.)
So, my question stated another way is: Does a nullMap equivalent already exist in Kotlin's standard library? And/or: is there a different standard way of doing this?
Finally, can the visually cleaner chaining approach be achieved in Kotlin, rather than either separate assignments (above) or nested function calls? For a moment I considered that you could add nullMap as an extension method on Any, but sometimes the receiver you're trying to invoke a method on is null (so that won't work).
We use safe call operator:
val foo: Foo? = ...
foo?.toA()?.toB()
Or
foo?.let(this::transform1)?.let(this::transform2)
Kotlin emphasis on null safety. There is an entire chapter in its manual describing related technics.