Hey. I can do `my?.chained?.call?.of?.operators?`a...
# getting-started
m
Hey. I can do `my?.chained?.call?.of?.operators?`and get null, if any of these is null. Is there a nice way of achieving the same for parameters? e.g.
Copy code
fun foo(a: Type1, b: Type2, c: Type3): Type4

val result: Type4? = foo(myA?, myB?, myC?) // is null if any of the parameters is null
g
There is a Jetbrains annotation to define a contract on a function if that's what you need
@Contract("null, null, null -> null") fun foo(...)
m
That seems to be the opposite of what I want 🙂 I want to leave the function alone, and just want to have syntactic suger for the caller.
e
at the moment, you can do something like
Copy code
val result = if (myA != null && myB != null && myC != null) {
    foo(myA, myB, myC)
} else null
val result = run {
    foo(myA ?: return@run null, myB ?: return@run null, myC ?: return@run null)
}
👍 1
g
Did you mean to avoid calling the
foo
method completely? Looks weird to me, the nullability of args as nothing to do with calling the method, even if I suppose there is some cases where you would want to do that. Also you could do a weird
?.let
embedded checks or just a simple
if (mA!= null && myB != null..)
e
there's also some Arrow monad thing
👌 1
👍 1
c
The first thing that comes to mind is to pass the params into a list, and then use something like
.any { it == null }
. An easier-to-understand solution might just be to use precondition checks at the start of the function on each parameter
Copy code
fun foo(a: Type1?, b: Type2?, c: Type3?): Type4? { 
    if(a == null) return null
    if(b == null) return null
    if(c == null) return null
    
    // at this point, all parameters have been smart-cast to non-null
    return Type4(a.toString() + b.toString() + c.toString())
}
m
Ok, then I'll hope for the Future. @Casey Brooks, I was also considering the list + any idea, but that seems to be unnecessary overhead. And the second suggestion has the drawback, that the method itself needs to deal with the null-logic.
thanks for the input everyone!
t
You could also write a wrapper function (or multiple for more/fewer parameters):
Copy code
fun <P1, P2, P3, R> runOrNull(
    param1: P1?, 
    param2: P2?, 
    param3: P3?, 
    block: (P1, P2, P3) -> R
): R? {
    return block(
        param1 ?: return null,
        param2 ?: return null,
        param3 ?: return null
    )
}

fun foo(a: Type1, b: Type2, c: Type3): Type4

val result: Type4? = runOrNull(myA, myB, myC, ::foo)
e
more
let
-like than
run
-like and would make sense to
inline
but yeah, things of that nature have been thrown around before (e.g. https://github.com/stupacki/MultiFunctions)
unfortunately you can't varargs it without losing type information