What's your opinion on using function/method refer...
# codingconventions
d
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️⃣ 3
l
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
Do you use references also for methods? e.g.
String::isNotEmpty
l
Yes
MyJsonObject::parse
d
Even if the type is complicated, e.g. due to generics?
Map<String, Int>::size
s
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
I’m on team lambda for kotlin. But I use method references in java
l
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
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
@ephemient @Jacob Can you explain why you prefer lambdas?
m
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
@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
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
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
a reference is too though
with the added complexity of having non-identity equals/hashCode, being serializable, etc.
m
@ephemient how about when passing by reference/lambda into a composable. Is the
equals
/`hashCode` important in that case?
e
no, the compose compiler analyzes where lambdas are stable based on what they capture
👍 1