Kotlin idiom for working with non-null object and non-blank String representation - conditional-statements

I have a nullable property (a Java object) that knows how to convert itself to a String, and if this representation is not empty, I would like to do something with it. In Java this looks like:
MyObject obj = ...
if (obj != null) {
String representation = obj.toString();
if (!StringUtils.isBlank(representation)) {
doSomethingWith(representation);
}
}
I'm trying to find the most idiomatic way of converting this to Kotlin, and I have:
with(obj?.toString()) {
if (!isNullOrBlank()) {
doSomethingWith(representation)
}
}
But it still feels like too much work for such a simple operation. I have this feeling that combining let, when, and with I can slim this down to something a bit shorter.
The steps are:
If the object (A) is not null
If the String representation (B) of object (A) is not blank
Do something with (B)
I tried:
when(where?.toString()) {
isNullOrBlank() -> builder.append(this)
}
But (1) it fails with:
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: #InlineOnly public inline fun
CharSequence?.isNullOrBlank(): Boolean defined in kotlin.text #InlineOnly public inline fun CharSequence?.isNullOrBlank(): Boolean defined in
kotlin.text
And even if it got past that, (2) it would want the exhaustive else, which I don't really care to include.
What's the "Kotlin way" here?

You can use the (since Kotlin 1.1) built-in stdlib takeIf() or takeUnless extensions, either works:
obj?.toString().takeUnless { it.isNullOrBlank() }?.let { doSomethingWith(it) }
// or
obj?.toString()?.takeIf { it.isNotBlank() }?.let { doSomethingWith(it) }
// or use a function reference
obj?.toString().takeUnless { it.isNullOrBlank() }?.let(::doSomethingWith)
For executing the action doSomethingWith() on the final value, you can use apply() to work within the context of the current object and the return is the same object, or let() to change the result of the expression, or run() to work within the context of the current object and also change the result of the expression, or also() to execute code while returning the original object.
You can also create your own extension function if you want the naming to be more meaningful, for example nullIfBlank() might be a good name:
obj?.toString().nullIfBlank()?.also { doSomethingWith(it) }
Which is defined as an extension to a nullable String:
fun String?.nullIfBlank(): String? = if (isNullOrBlank()) null else this
If we add one more extension:
fun <R> String.whenNotNullOrBlank(block: (String)->R): R? = this.nullIfBlank()?.let(block)
This allows the code to be simplified to:
obj?.toString()?.whenNotNullOrBlank { doSomethingWith(it) }
// or with a function reference
obj?.toString()?.whenNotNullOrBlank(::doSomethingWith)
You can always write extensions like this to improve readability of your code.
Note: Sometimes I used the ?. null safe accessor and other times not. This is because the predicat/lambdas of some of the functions work with nullable values, and others do not. You can design these either way you want. It's up to you!
For more information on this topic, see: Idiomatic way to deal with nullables

Related

Convert Comparable<*> but get error inferred type is Any? but Nothing was expected

I am trying to convert this piece of java code to kotlin
public int compare1(Comparable c, Object o) {
return c.compareTo(o);
}
to kotlin code:
fun compare1(c: Comparable<*>, o: Any?): Int {
return c.compareTo(o)
}
But get error
Type mismatch: inferred type is Any? but Nothing was expected
Any reason why this error occurs? Thanks
This code in Java shows a warning, because the compiler can't know if provided comparable can compare itself to provided object. Compiler still allows this, but it doesn't guarantee it won't throw an exception at runtime.
Its equivalent in Kotlin is either:
fun compare1(c: Comparable<Any?>, o: Any?): Int {
return c.compareTo(o)
}
With this code you'll have to do unchecked casts when calling the function. Or alternatively:
fun compare1(c: Comparable<*>, o: Any?): Int {
return (c as Comparable<Any?>).compareTo(o)
}
Note it doesn't solve the problem. You can call this function passing an integer and a string and then you will get an exception. So use this code only if the logic of your application guarantees you always pass matching objects to the function.
Even better, try to redesign your code to use generics in a type-safe manner. In that case your function would become:
fun <T> compare1(c: Comparable<T>, o: T): Int {
return c.compareTo(o)
}
This function is type-safe, so it doesn't allow using comparables with incorrect types. It may not work as a direct replacement of your Java function though, as the original function didn't care about the type safety. You may need to redesign other parts of your code to use this function.

Different results on similar code with safe call operator in Kotlin

I'm new to Kotlin and these two below codes give different results.
fun main() {
var name: String? = "Rajat"
name = null
print(name?.toLowerCase())
}
Output: Compilation Error (illegal access operation)
fun main() {
var name: String? = null
print(name?.toLowerCase())
}
Output: null
When you do this assignment:
name = null
name is smart casted to Nothing?, which is problematic. Nothing is the subtype of every type, and so you become able to call any accessible extension functions of any type, according to the overload resolution rules here.
Compare:
fun main() {
var name: String? = "Denis"
name = null
print(name?.myExtension()) // works
val nothing: Nothing? = null
print(nothing?.myExtension()) // also works
}
fun Int.myExtension(): Nothing = TODO()
Note that allowing you to call any extension function on Nothing is perfectly safe - name is null anyway, so nothing is actually called.
Char.toLowerCase and String.toLowerCase happen to be two of the extension functions that are accessible, and you can call both on name, which is now a Nothing?. Therefore, the call is ambiguous.
Note that smart casts only happens in assignments, not in initialisers like var name: String? = null. Therefore, name is not smart casted to Nothing? in this case:
fun main() {
var name: String? = null
print(name?.toLowerCase()) // better to use lowercase(), toLowerCase is deprecated!
}
For the reason why, see my answer here.
The actual error on your first example is
Overload resolution ambiguity: public inline fun Char.toLowerCase(): Char defined in kotlin.text public inline fun String.toLowerCase(): String defined in kotlin.text
Looks like the Kotlin compiler is being too smart for its own good here. What's happening, is that on the second example, you are explicitly defining a variable of type String? and assigning it some value (null in this case, but that doesn't matter).
On the second example, you are defining a variable of some type, and then telling the compiler "hey, after this assignment, name is always null". So then it remembers the more-specific "name is null" instead of "name is String?".
The standard library has two methods called toLowerCase, one on Char and one on String. Both of them are valid matches now, and the compiler is telling you it doesn't know which one to pick. In the end that won't matter, because name is null, but the compiler apparently doesn't use that final thing to throw out the method call altogether.

is there any way I send a nullable Function<T,R> as parameter in Kotlin?

I am trying to use the public interface Function (as I learned it in Java) in Kotlin.
For this I created my method
fun foo(input: List<String>, modifier1: Function<List<String>>? = null){
}
as far I remember here I should be able to do modifier1.apply(input)
but seems like it is not possible (it is possible to do modifier1.apply{input} though)
Reading more about it I found this:
Kotlin: how to pass a function as parameter to another?
So I changed my method signature to this:
fun foo(input:String, modifier2: (List<String>) -> (List<String>){
}
Here I am able to do modifier2(input)
and I can call foo this way
service.foo(input, ::myModifierFunction)
where
fun myModifierFunction(input:List<String>):List<String>{
//do something
return input
}
So far this seems possible but it is not acceptable to have the function reference as nullable, is there any way I can do that? or use Function ?
You were using kotlin.Function instead of java.util.function.Function in your first example. Note that the latter takes 2 generic types: 1 for the incoming parameter and 1 for the resulting one.
The apply method you saw is the default Kotlin one: apply, not the one of Java's Function-interface.
If you really want to have the Java-function as nullable type the following should work:
fun foo(input: List<String>, modifier1: java.util.function.Function<List<String>, List<String>>? = null) {
modifier1?.apply(input) ?: TODO("what should be done if there wasn't passed any function?")
}
Kotlin variant for the same:
fun foo(input: List<String>, modifier1: ((List<String>) -> List<String>)? = null) {
modifier1?.invoke(input) ?: TODO("what should be done if there wasn't passed any function?")
}
Maybe also a default function, such as { it } instead of null might better suite your needs? (Java variant would be Function.identity()):
// java modifier1 : Function<List<String>, List<String>> = Function.identity()
// kotlin modifier1 : (List<String>) -> List<String> = { it }
You can make the reference nullable simply with ? — the only wrinkle is that the whole function type needs to be in parens first:
fun foo(input: String, modifier2: ((List<String>) -> List<String>)? = null) {
}
As required, modifier2 is optional; if specified, it may contain null, or it may contain a function taking and returning a list of strings.
As mentioned in another answer, kotlin.Function is not the same as java.util.function.Function — though in practice you shouldn't need to refer to either directly, as the -> notation is simpler.
If you want to pass in a function that takes List<String> as its parameter and returns nothing meaningful, the type for you is Function1<List<String>, Unit>. The method name for invoking a function is invoke(), which you could also do with just regular parentheses, if it wasn't nullable. All in all, your code could look something like this:
fun foo(input: List<String>, modifier1: Function1<List<String>, Unit>? = null) {
modifier1?.invoke(input)
}
The 1 in the typename of Function1 means that it's a one parameter function, there's also Function0, Function2, etc.
The Function type on its own is not something you can use to call that function, as it's an empty marker interface. All functions implement this regardless of how many parameters they have.

Is there a simple null safe operator for Kotlin function references?

I'd like to pass a function reference on a nullable object. To take an Android example, say I want to use Activity#onBackPressed from a fragment that is a child of that actvity.
If I wanted to invoke this function, I could easily do
activity?.onBackPressed()
However, say I wanted to pass that as a reference instead:
val onBackPressedRef = activity::onBackPressed
This gives the familiar null safe error of Only safe or non null assserted calls are allowed...
I can get the error to go away with the following, but using !! is obviously not ideal:
val onBackPressedRef = activity!!::onBackPressed
Attemping activity?::onBackPressed was my first instinct, but this also breaks with several errors, where the interpreter seems confused.
val onBackPressedRef = activity?.let { it::onBackPressed }
This last variation works, but it's a lot more ugly than just using ?::. I checked all the docs I could find, but I feel like I'm missing something. Any ideas?
You are right, there is no ?:: operator in Kotlin.
You have several alternatives:
1. let and run
Thus, you have to use a helper function. Instead of let(), you can also use run(), making the expression a tiny bit shorter:
val onBackPressedRef = activity?.let { it::onBackPressed }
val onBackPressedRef = activity?.run { ::onBackPressed }
But keep in mind that either way, the invocation will be more verbose, too:
onBackPressedRef?.invoke(args)
Thus you should ask yourself, if this is really what you want, or if a no-op function call is also acceptable.
2. Closures
You could use a closure -- this will change semantics however:
val onBackPressedRef = { activity?.onBackPressed() }
Here, onBackPressedRef is not nullable anymore, so you can call it using the () operator, and in case of null activity it will have no effect.
3. Helper function
If function references with nullable objects are something you encounter a lot, you can write your own little abstraction:
// Return type: () -> Unit
fun <T> funcRef(obj: T?, function: T.() -> Unit) = { obj?.function() }
This trades a different syntax for a non-null function variable:
// activity can be null
val onBackPressedRef = funcRef(activity, Activity::onBackPressed)
// Callable directly
onBackPressedRef()

Difference between Any type and Generics in Kotlin

Suppose I have the following function definition.
fun<T> parse(a: Any): T = when (a) {
is String -> a
else -> false
}
I guessed it should be valid. However, the IntelliJ IDEA linter shows a type mismatch error
That being said, I would change the return type of my parse function to Any, right? So that, what is the difference between using Any type and Generics in Kotlin? In which cases should use each of those?
I did read the following question but not understood at all about star-projection in Kotlin due to the fact I am quite new.
Your return type it defined as T, but there is nothing assuring that T and a:Any are related. T may be more restrictive than Any, in which case you can't return a boolean or whatever you provided for a.
The following will work, by changing the return type from T to Any:
fun<T> parse(a: Any): Any = when (a) {
is String -> a
else -> false
}
Any alternate option, if you really want to return type T:
inline fun<reified T> parse(a: Any): T? = when (a) {
is T -> a
else -> null
}
Your example does not use T and thus it's nonsense to make it generic anyways.
Think about this: As a client you put something into a function, e.g. an XML-ByteArray which the function is supposed to parse into an Object. Calling the function you do not want to have it return Any (Casting sucks) but want the function return the type of the parsed object. THIS can be achieved with generics:
fun <T> parse(xml: ByteArray): T {
val ctx: JAXBContext = JAXBContext.newInstance()
val any = ctx.createUnmarshaller().unmarshal(ByteArrayInputStream(xml))
return any as T
}
val int = parse<Int>("123".toByteArray())
val string = parse<String>("123".toByteArray())
Look at the method calls: You tell with generics what type is expected to be returned. The code is not useful and only supposed to give you an idea of generics.
I guessed it should be valid
Why would it be? You return a String in one branch and a Boolean in the other. So the common type for the entire when expression is Any and that's what the compiler (and IDEA) says is "found". Your code also says it should be T (which is "required").
Your generic method should work for any T, e.g. for Int, but Any isn't a subtype of Int and so the code isn't valid.
So that, what is the difference between using Any type and Generics in Kotlin?
This is like asking "what is the difference between using numbers and files": they don't have much in common in the first place. You use generics to write code which can work with all types T (or with all types satisfying some constraint); you use Any when you want the specific type Any.