https://kotlinlang.org logo
#codingconventions
Title
# codingconventions
d

David Kubecka

12/01/2023, 3:00 PM
What's your opinion on using function/method references instead of lambdas for scope or library functions? Most of the code I've seen uses lambdas, e.g.
Copy code
myList.map { transform(it) }
myString.takeIf { it.isNotEmpty() }
As an alternative, however, one could also use function/method references, e.g.
Copy code
myList.map(::transform)
myString.takeIf(String::isNotEmpty)
Which convention do you prefer and why?
2️⃣ 2
l

LeoColman

12/01/2023, 3:11 PM
I use references as much as I can. I think it takes less space and is more clear of that I'm trying to do
If what I want is "Apply this function to this code", I think it's very fair to just reference the function instead of opening up a lambda
So yeah, I'll always use
Copy code
daoObjects.map(::toJsonResponse).filter(::onlyErrors)
I think it's the same, convention-wise. IntelliJ can even replace it for you on-demand
d

David Kubecka

12/01/2023, 3:21 PM
Do you use references also for methods? e.g.
String::isNotEmpty
l

LeoColman

12/01/2023, 3:22 PM
Yes
MyJsonObject::parse
d

David Kubecka

12/01/2023, 3:28 PM
Even if the type is complicated, e.g. due to generics?
Map<String, Int>::size
s

Shawn

12/01/2023, 3:37 PM
sometimes types are just long (and sometimes even need to be qualified too), so in some cases it's much better for DX to just use a lambda
Copy code
.map(AbstractMap.SimpleEntry::getKey)
.map { it.key }
j

Jacob

12/01/2023, 3:37 PM
I’m on team lambda for kotlin. But I use method references in java
l

LeoColman

12/01/2023, 4:01 PM
Agree 100% with @Shawn. It's a very case-by-case situation
> Even if the type is complicated, e.g. due to generics?
Map<String, Int>::size
That is a very case-by-case situation. I think generics are complex enough to require their own lambda `{}`block 🙂
e

ephemient

12/02/2023, 12:30 AM
I almost always use lambdas,
this
-bound references might be the only ones I use occasionally
if they're inlined it doesn't matter either way, but if they're not,
::
actually involves a bit more machinery (
foo::bar == foo::bar
,
{ foo.bar() } != { foo.bar() }
) which is useful in some scenarios but unnecessary in most
d

David Kubecka

12/03/2023, 9:28 PM
@ephemient @Jacob Can you explain why you prefer lambdas?
m

Mark

12/06/2023, 8:05 AM
Also consider when
foo
is using
lazy
delegate: https://pl.kotl.in/SFXtWGMzr i.e. we avoid an unnecessary instantiation by using a lambda.
Copy code
val foo1 by lazy {
    println("foo1 instantiated")
    Any()
}
val block1 = foo1::toString
println("foo1")
val foo2 by lazy {
    println("foo2 instantiated")
    Any()
}
val block2 = { foo2.toString() }
println("foo2")
output:
Copy code
foo1 instantiated
foo1
foo2
d

David Kubecka

12/06/2023, 8:50 AM
@Mark That's quite an edge case but thanks anyway! So what is the takeaway from this? That using lambdas is slightly better/safer because it prevents an unnecessary initialization of a lazy property?
m

Mark

12/06/2023, 8:51 AM
right. I came across this case in my own code the other day. I wondered whether the compiler would be smart enough to not instantiate so tested it out.
Foo
in my case is an event handler, so it only needs to be instantiated when there is an event, hence
lazy
.
r

ribesg

12/06/2023, 3:38 PM
On the JVM, when passing a lambda to a function, isn't the lambda compiled as a new Java class? I always preferred using references for that reason
e

ephemient

12/06/2023, 3:40 PM
a reference is too though
with the added complexity of having non-identity equals/hashCode, being serializable, etc.
m

Mark

12/07/2023, 4:34 AM
@ephemient how about when passing by reference/lambda into a composable. Is the
equals
/`hashCode` important in that case?
e

ephemient

12/07/2023, 4:42 AM
no, the compose compiler analyzes where lambdas are stable based on what they capture
👍 1
3 Views