Do most people stay away from using kotlin standar...
# announcements
c
Do most people stay away from using kotlin standard functions? I just joined a project where they advise to not use them as it adds overhead to having to think about what's actually going on. I understand that these functions are just another tool in your toolbelt, and so it's up to everyones discretion on whether or not we should use that tool, but does anyone have similar feelings about typically not using them? Converting 5 lines to 4 doesn't seem like an improvement most times. Is there a good reason to use any of them? I've read that functions like let and apply are probably the most useful so that you don't have to do
Copy code
myobject.somethingInner.somethingNested.setter1 = true
myobject.somethingInner.somethingNested.setter2 = false
myobject.somethingInner.somethingNested.setter3 = false
That seems like a legitimate use case to me to not have to repeat so you can do
Copy code
myobject.somethingInner.somethingNested.apply {
setter1 = true
setter2 = false
setter3 = false
}
I also read that this makes things thread safe. So while that sounds good. I don't know what that actually means. Is my first statement not thread safe?
a
re. thread safety, that's situational. If the object returned by
myobject.somethingInner.somethingNested
can change between each of those lines of code, you're setting values on different objects
It's also just kind of unnecessary to do that pointer chasing more than once, if only because it's much noisier to read and introduces opportunities for error in repetition that don't need to be there. If you really want to avoid the
apply
for some reason, do a
Copy code
val nested = myobject.somethingInner.somethingNested
nested.setter1 = true
nested.setter2 = false
// ...
and get the same effect
d
There are actual some cases where Standard functions like apply are very useful. For example the Calendar in Android. You want to know which Day of the week the 27.8.2022 is.
val calendar = Calendar.getInstance()
calendar.set(2022,8,27)
val dayOfTheWeek = calendar.get(Calendar.DAY_OF_WEEK)
With Kotlin Standard functions you can set the value you want with initialization and immediately retrieve the value you want.
val dayOfTheWeek = Calendar.getInstance().apply { set(2022,8,27) }.get(Calendar.DAY_OF_WEEK)
c
@Adam Powell thanks for the clear expalanation there. @Dominik wuttke while I admit that the apply may have a slight edge in your example there, I would say that it's a very slight (almost negligible) improvement IMO. Reading the first two lines instantly tells me whats going on, while reading the apply{set()}.get() takes me a few seconds to make sure I understand it.
a
an advantage of using scoping functions in cases like the above is that the shape of the code makes it harder for a reference to an object in a bad state to escape to somewhere else. Someone can't write,
doStuffWith(calendar)
on a line of code before
calendar
is fully initialized into a known good state without going out of their way and making the code look suspicious. Limiting the scope of object references helps you code defensively.
c
@Adam Powell lost me a bit there. "the shape of the code makes it harder for a reference to an object in a bad state to escape to somewhere else."?
d
I wouldn't blame apply/let/run for "overhead to having to think about what's actually going on".
d
I agree with David. Your original example seems like a law of demeter violation. That alone can lead to some confusing code. There is nothing wrong with using a machete in the Jungle. But you would not use it in a nursery.
Let me put it this way. A cup of coffee a day is good for you, but not 4 pots. Over use of the standard functions is the issue. Many
.run
s over the use of
.let
. Not using the ability to rename
it
with something meaningful.
d
Exactly @dewildte. One excellent way (mostly known for getting rid of comments) to reduce the "overhead to having to think about what's actually going on" is to have pretty small functions/methods with descriptive names.
c
Understood, but why if you're doing a null check for example it is recommended to do it with a
?let
, but it also works just fine if you
?apply
?also
?run
This is what I mean by added overhead. If I read any of those it would take me a second or two longer to read to make sure I understand it vs just using an
if (thing != null) { }
. In that case I actually think the if statement is more expressive in terms of intent.
b
it’s all a matter of preference IMO. I think the standard functions are great. Just be sure to rename the
it
variable when/if you’re doing any sort of nesting. And if you’re doing nesting… have a good reason.
👍 1
d
"If this is not null" vs "IF THIS IS NOT NULLL!!!"
Plus your hands to consider. The more you have to type the more strain on your hands.
Try to consider as many variables around the matter as possible before casting judgment upon the standard functions.
One thing I did was learn how to make a programming language. Doing so you begin to appreciate the languages features more.
b
if (someMemberVariable != null)
doesn’t even prevent you from having to do
someMemberVariable!!
within the if block since because it’s a member variable it’s value can change. So for me, this:
Copy code
if (someMember != null) {
    someMember!!.value = x
    someMember!!.whatever()
}
isn’t as nice as:
Copy code
someMember?.let {
    it.value = x
    it.whatever()
}
💯 1
👍 2
but there’s a difference between avoiding a null pointer and doing something different when a variable is null. Sometimes the appropriate thing to do is check to see if something is null. In which case
if (whatever == null)
makes sense. But other times you want to just change some state of a variable that may be null sometimes and it’s safe to ignore it when it’s null.
💯 1