How to define a oneline function calling a nullable variable function - kotlin

If I have something like:
fun showProgressView() = ultraRecyclerView?.showProgressBar()
it says that it returns Unit? and not Unit (edited)
-----EDIT-----
One way can be
fun showProgressView() = ultraRecyclerView?.showProgressBar() ?: Unit
but it looks not right for me.
Another way:
fun showProgressView() { ultraRecyclerView?.showProgressBar() }
But I cant find a way for android studio maintain that format.

If you use the short expression form of a function, the inferred result type of the expression determines the function return type. If that is a platform type from Java, it could be nullable. If it is a Kotlin type then it will know the correct nullability.
But since you use the safe operator ?. you are saying for sure it could be nullable. And if the result is null or Unit then that gives the inferred result type of Unit?
Which is odd, but is exactly what you are saying. Therefore, either use a normal function body with { .. } or give the function an explicit return type if possible.
fun showProgressView(): Unit { ultraRecyclerView?.showProgressBar() }
You can also erase the nullability, by creating an extension function on Unit?:
fun Unit?.void() = Unit
And use it whenever you want to fix the return type:
fun showProgressView() = ultraRecyclerView?.showProgressBar().void()

IntelliJ IDEA / Android Studio do not appear to have a setting to keep the style of a block body function on a single line. Even so, you can use run to get around this:
fun showProgressView() = run<Unit> { ultraRecyclerView?.showProgressBar() }
Normally you do not need to add explicit type arguments to run but in this case providing them gives you the desired method signature (return type of Unit and not Unit?).
Note: This answer is adapted from a comment I gave to why assignments are not statements.

Related

mockkStatic for extension method with generic parameter: "Not enough information to infer type variable T"

FYI: I'm currently using Mockk-1.12.4 and Kotlin-1.6
I've got an extension method that returns an object of type T:
fun <T> Entity.selectReferenceAsSingleObject(referenceName: String): T {
return this.selectReferencesByName(referenceName).single().asObjet() as T
}
This is defined as top level function in an Extentions.kt file (so not a class). I'm wanting to mock this with MockK by using mockkStatic
mockkStatic(Entity::selectReferenceAsOptionalSingleObject)
However I'm getting the error:
Not enough information to infer type variable T
because it cannot work out what type I should be mocking. I've tried adding my type parameter in a bunch of places
mockkStatic<KFunction<MyType>>(Entity::selectReferenceAsSingleObject)
mockkStatic<MyType>(Entity::selectReferenceAsSingleObject)
mockkStatic(Entity<KFunction<MyType>>::selectReferenceAsSingleObject)
mockkStatic(Entity<MyType>::selectReferenceAsSingleObject)
mockkStatic(Entity::<KFunction<MyType>>selectReferenceAsSingleObject)
mockkStatic(Entity::<MyType>selectReferenceAsSingleObject)
mockkStatic(Entity::selectReferenceAsSingleObject<KFunction<MyType>>)
mockkStatic(Entity::selectReferenceAsSingleObject<MyType>)
mockkStatic(Entity::selectReferenceAsSingleObject as KFunction<MyType>)
mockkStatic(Entity::selectReferenceAsSingleObject as MyType)
But nothing works and it either tells me the same error or tells me that type arguments are not allowed there. I'm not sure what I need to do to fix my syntax as IntelliJ isn't giving me any hints so I feel kind of stuck. Any help would be appreciated.
Try this:
mockkStatic("your.package.YourFileExtensionKt")
you can also give the file a nice name:
#file:JvmName("Extension")
would look like this:
mockkStatic("your.package.Extension")
anyway for the test to work you must use a mock in the extended class, in this case Entity, it would look like this:
#Test
fun test() {
val entity : Entity = mockk(relaxed = true)
every { entity.selectReferenceAsSingleObject<Any>(any()) } returns "whatever"
val result = entity.selectReferenceAsSingleObject<Any>("test")
assertEquals("whatever", result)
}

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()

Using implicit variable in function literal

I started reading Kotlin course book. I stopped on function literals. Here I have a code:
val printMessage = { message: String -> println(message) }
printMessage("hello")
printMessage("world")
Then I have an information that I can omit parameter type:
{ message -> println(message) }
And now I have next step:
"In fact, Kotlin has a neater trick. If there is only a single parameter and the type can beinferred, then the compiler will allow us to omit the parameter completely. In this case, itmakes the implicit variable it available:
{println(it)}
And now after using this code I get an error "unresolved reference: it" and "too many arguments for public operator fun invoke(): ??? defined in kotlin.Function()":
val printMessage = {println(it)}
printMessage("print something")
My question is how to use implicit variable in single paramenter function literal?
See the Kotlin documentation, specifically where it says:
If the compiler can figure the signature out itself, it is allowed not
to declare the only parameter and to omit ->. The parameter will be
implicitly declared under the name it.
In your case, the compiler (at least up to current version 1.3.31) can't figure the signature out itself:
val printMessage = {println(it)}
But if you give your printMessage variable an explicit type, it will work:
val printMessage: (String) -> Unit = { println(it) }
You always need to provide all information about all generic parameters. If you want to omit it, it needs to be inferable from some other part of the code. The only information you provide though is that you want printMessage to be a lambda. So it assumes it to be of type ()->Unit. This is because you don't declare a parameter for the lambda itself. The implicit parameter it is therefore not usable.
val printMessage = { it: String -> println(it) }
val printMessage: (String)->Unit = { println(it) }
Simply put: If you're inside a lambda with one parameter, the implicit it can be used as this parameters name, but a reference named it within the body of the lambda doesn't declare the single parameter.

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.