https://kotlinlang.org logo
d

dm6801

01/09/2021, 8:27 AM
Hello kotliners,
Copy code
fun main() {
    fun fun1(name: String) = println("Hello $name")
    val fun2 = { name: String -> println("Hello $name") }
    function(::fun1)
    function(fun2)
}

fun function(callback: (name: String) -> Any) {
    //some complicated calculation
    callback("username")
}
Which one would you use, and why?
e

ephemient

01/09/2021, 9:02 AM
if there was a reason it couldn't be called directly, such as
Copy code
val name: String?
, then I would generally prefer
Copy code
fun fun1(name: String)
name?.let { fun1(it) }
over
?.run
or
::fun1
or
val fun1
d

dm6801

01/09/2021, 9:09 AM
this is a simplified example of a more complicated use-case, I call a function with lambda parameters, and I pass in the local function using a reference (::). I am editing my original question to illustrate that
e

ephemient

01/09/2021, 9:16 AM
my opinion: very strongly prefer
fun fun1()
over
val fun1 = {}
. weakly prefer
function { fun1(it) }
over
function(::fun1)
☝️ 2
d

dm6801

01/09/2021, 9:37 AM
I don't have too much experience with bytecode, but here is a comparison if someone more experienced would like to weigh in: fun1 declaration:
L0
LINENUMBER 7 L0
GETSTATIC Test$test1$1.INSTANCE : LTest$test1$1;
ASTORE 1
fun1 invocation:
L1
LINENUMBER 8 L1
ALOAD 0
GETSTATIC Test$test1$2.INSTANCE : LTest$test1$2;
CHECKCAST kotlin/jvm/functions/Function1
INVOKEVIRTUAL Test.func (Lkotlin/jvm/functions/Function1;)V
fun2 declaration:
L0
LINENUMBER 13 L0
GETSTATIC Test$test2$fun2$1.INSTANCE : LTest$test2$fun2$1;
CHECKCAST kotlin/jvm/functions/Function1
ASTORE 1
fun2 invocation:
L1
LINENUMBER 14 L1
ALOAD 0
ALOAD 1
INVOKEVIRTUAL Test.func (Lkotlin/jvm/functions/Function1;)V
looks like func1 has an extra GETSTATIC in the invocation phase also, regarding your comment on function { func1(it) } vs. function(::func1) - it appears they are bytecode-equivalent, apparently just syntactic sugar overall, looks to me like a matter of personal preference and code styling
e

ephemient

01/09/2021, 10:31 AM
not 100% bytecode equivalent - the wrapper lambda class generated for
::func1
has some different metadata and serializability than
{ func1(it) }
- but close enough
yes, it is a matter of preference. I feel that using the
{ }
syntax is more consistent than sometimes using
::
and sometimes not due to ambiguities such as overload resolution
👍 2
similarly with
fun
vs
val
, especially as
val
is more awkward to put generics or type annotations on
there are some cases where
val
is necessary, such as
Copy code
val handler = Runnable { ... }
register(handler)
unregister(handler)
when the exact same instance needs to be retained, but I have never seen that come up with Kotlin APIs, only Java interop
v

Vampire

01/09/2021, 1:59 PM
You shouldn't compare bytecode to find the better of two constructs. Byte code is not part of the API, it could change anytime. Also that would not even be micro-optimization which you should avoid already, but nano-optimization. 80% of the runtime of a program is spent in 20% of the code and there is not much point in optimizing the other 80%. 1. Make your code work (optimally with tests, especially for the latter steps) 2. Make your code nice by refactoring 3. If you then have an actual measured performance or memory problem, optimize exactly there.
✔️ 1
4
d

dm6801

01/09/2021, 5:28 PM
my concern when posting this was with your 2nd clause "Make your code nice" - first I wanted to make sure I was not overlooking functionality, and then get feedback on which syntax is more likeable, or agreed upon, by other people
v

Vampire

01/09/2021, 6:46 PM
Sure, just mentioning in general as you said you looked at the bytecode. 🙂
d

dm6801

01/09/2021, 7:23 PM
You still haven't answered the original question though, which one would you rather use?
v

Vampire

01/09/2021, 7:23 PM
Well, I don't have much to add what the others said. It depends on the situation.
s

string randomizer

01/11/2021, 10:03 PM
IMHO I would use
function(::fun1)
cause it much more clear that it is a callback , than
function(fun2)
however a closure is more powerful cause you can combine closures
function(fun2.then(fun3))
also in kotlin there is special syntax for closures which is very clear
Copy code
function {
        name ->
        println("Hello $name")
    }
if the last param in the method is a closure you can skip the
()
v

Vampire

01/11/2021, 11:14 PM
Actually there is no such thing as a Closure in Kotlin, it is a lambda expression. Closure is a term from other language like Groovy. 😉
8 Views