Michael Friend
02/05/2020, 4:48 PMprivate val _listOfStrings = mutableListOf<String>()
val listOfStrings : List<String> = _listOfStrings
// and
private val _listOfStrings = mutableListOf<String>()
val listOfStrings : List<String>
get() = _listOfStrings
Which one is better convention? I like how the first one is more concise but examples often show the secondMichael Friend
02/07/2020, 3:12 PMrun
with the elvis operator as a sort of guard statement like in iOS?
I’ve wanted a way to do a sort of side effect like logging when using ?:
to exit a function
Something like
fun takesNullables(val string: String?) {
val notNull = string ?: run {
println("arg was null")
return
}
}
// Or a more complicated usage
fun gaurdTest(val nums: List<Int>, val person: Person) {
val firstEvent = nums.firstOrNull { it % 2 == 0 } ?: run {
println("no evens in $nums")
return
}
// Or
val streetName = person?.address?.streeName ?: run {
println("street name not found")
return
}
}
Kroppeb
02/10/2020, 2:05 PMfun addStatement(statement: Statement?){
statement?.let{
statements.add(it)
}
}
or less indentation
fun addStatement(statement: Statement?){
statement?:return
statements.add(statement)
}
or just old reliable
fun addStatement(statement: Statement?){
if(statement != null)
statements.add(statement)
}
Nick Halase
02/12/2020, 8:02 PMfooExt.kt
FooExt.kt
, etc?Ellen Spertus
02/17/2020, 9:20 PM// 1
fun calculateHour(h: Int, period: String?): Int =
period?.let {
when(it) {
"am" -> if (h == HOURS_PER_PERIOD) 0 else h
"pm" -> (h % HOURS_PER_PERIOD) + HOURS_PER_PERIOD
else -> h // should not happen
}
} ?: h
}
// 2
fun calculateHour(h: Int, period: String?): Int =
if (period == null) {
h
} else when (period) {
"am" -> if (h == HOURS_PER_PERIOD) 0 else h
"pm" -> (h % HOURS_PER_PERIOD) + HOURS_PER_PERIOD
else -> h // should not happen
}
}
dumptruckman
03/03/2020, 3:25 PMdumptruckman
03/13/2020, 7:31 PMval things = getThings() orIfEmpty listOf(SingleThing())
or
val things = getThings().letIfEmpty { listOf(SingleThing()) }
or does someone have a better solution?dumptruckman
03/26/2020, 8:36 PMdavid.bilik
03/27/2020, 11:30 AMFlow
type? eg. im observing users from database, should i name it like
fun users() : Flow<List<User>>
or
fun observeUsers() : Flow<List<User>>
or
fun usersChanges() : Flow<List<User>>
or
fun getUsersStream() : Flow<List<User>>
?
There is a lot of options and im curious about the best practicesdaphillips
04/01/2020, 12:10 PMname
?
sealed class Things {
abstract val name: String
data class ThingA(val x: Int, val y: String) : Things() {
override val name = "foo"
}
data class ThingB(z: Double) : Things() {
override val name = "bar"
}
}
or
sealed class Things(val name: String) {
data class ThingA(val x: Int, val y: String) : Things("foo")
data class ThingB(z: Double) : Things("bar")
}
Michael Pohl
04/15/2020, 7:33 AM.not()
postfix over the prefix !
for a "is not" check, when not?
I can't finda good guideline, and for me personally, the prefixed !
reads easier, but that might just because I'm used to it. Also it's related to !=
which I wouldn't want to repace with (a == b).not()
...Ellen Spertus
05/04/2020, 10:50 PM// 1
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> {
val nickname = viewModel.nickname
return CursorLoader(
contactActivity,
ContactsContract.Contacts.CONTENT_URI,
PROJECTION,
SELECTION,
arrayOf(
nickname, // just the nickname
"$nickname %", // first name
"% $nickname", // last name
"% $nickname %" // middle name
),
null
)
}
or
// 2
override fun onCreateLoader(loaderId: Int, args: Bundle?) =
viewModel.nickname.let { nickname ->
CursorLoader(
contactActivity,
ContactsContract.Contacts.CONTENT_URI,
PROJECTION,
SELECTION,
arrayOf(
nickname, // just the nickname
"$nickname %", // first name
"% $nickname", // last name
"% $nickname %" // middle name
),
null
)
}
sindrenm
05/07/2020, 9:29 AMval string: String? = "possibly-null"
Which of the following do people prefer to get either the value or an empty string if it's null?
val stringOrEmpty: String = string ?: ""
1️⃣
or
val stringOrEmpty: String = string.orEmpty()
2️⃣Dmitry Kandalov
05/15/2020, 9:57 AM.toString()
but you can’t call it “toString” because it’s shadowed by Object#toString
?JP
05/23/2020, 2:20 PMcheckNotNull(x).also {
// do something like..
it.prop = y
// ...
}
2.
x?.apply {
// do something like..
it.prop = y
// ...
} ?: throw IllegalStateException()
bsimmons
07/27/2020, 12:46 PM// Why is it that we are encouraged to add spaces before EVERY lambda?
// Seems to me like the spaces arbitrarily break up this expression.
list.filter { it < 10 }.map { it * it }
// This is the long-form syntax, right?
list.filter({ it < 10 }).map({ it * it })
// So after a little syntactic sugar, we should end up like this?
list.filter{ it < 10 }.map{ it * it }
Fabian Braun
08/03/2020, 10:15 AM.let
in particular)
Sometimes I have a hard time to decide about when to use .let
and when local variables should be preferred. Consider the example from https://kotlinlang.org/docs/reference/scope-functions.html#let which reads like:
val numbers = listOf("one", "two", "three", "four")
val modifiedFirstItem = numbers.first().let { firstItem ->
println("The first item of the list is '$firstItem'")
if (firstItem.length >= 5) firstItem else "!" + firstItem + "!"
}.toUpperCase()
println("First item after modifications: '$modifiedFirstItem'")
It could be rewritten to:
val numbers = listOf("one", "two", "three", "four")
numbers.first().let { firstItem ->
println("The first item of the list is '$firstItem'")
if (firstItem.length >= 5) firstItem else "!" + firstItem + "!"
}.toUpperCase().let { modifiedFirstItem ->
println("First item after modifications: '$modifiedFirstItem'")
}
However, in my opinion the second .let
makes the code less readable in this second snippet.
I have heard people say that local variables are not good kotlin-style and you should be using scope-functions but I couldn’t find any resources for that claim. Would be grateful for style-recommendations / resources on that.Sam
08/14/2020, 3:09 AMMarc Knaup
08/22/2020, 2:11 PMfun CurrencyCode(value: String): CurrencyCode // throws if invalid
fun CurrencyCodeOrNull(value: String): CurrencyCode? // null if invalid
2️⃣
fun CurrencyCode.Companion.parse(value: String): CurrencyCode // throws if invalid
fun CurrencyCode.Companion.parseOrNull(value: String): CurrencyCode? // null if invalid
3️⃣
fun String.toCurrencyCode(): CurrencyCode // throws if invalid
fun String.toCurrencyCodeOrNull(): CurrencyCode? // null if invalid
agu
08/22/2020, 9:26 PMEither
alongside with Future
and the map
function. I've watched the presentations of Elizarov (which are excellent by the way), but couldn't imagine how to replace the Either
. Thanks in advance.Marc Knaup
09/01/2020, 2:23 PMnull
if it completes?
interface Foo
interface FooProvider { fun provide(): Foo? }
fun provideFoo(providers: List<FooProvider>): Foo? {
for (provider in providers)
provider.provide()?.let { return it }
return null
}
I miss something like providers.firstNonNullMapped { it.provide() }
(and with a better name).Czar
09/04/2020, 10:45 AMJson {}
builder, until I noticed that intellij imported wrong class via star import before I got to Json {}.
After this I'm reverting the style config, star imports are evil and when one wants them, this needs to be explicit. It was quite unexpected when JB introduced the convention.
I did give it a chance, but nope, import bla.bla.*
default was evil, is evil and probably will remain so while imports exist 🙂Marc Knaup
10/13/2020, 12:12 AMa.id == b.id
)
• both entities are completely equal (a.id == b.id && a.prop1 == b.prop1 && …
)
I can’t decide whether I should implement equals
as comparing merely IDs or comparing entire entities.
1️⃣ Equality by entity IDs
• If compare IDs I cover common cases like if (sender != recipient) sendNotification(…)
and it reads very natural.
• It’s also more performant because in most cases you don’t need to compare entire entities.
• For Set<Entity>
typically also the ID is compared, meaning you want to have one entry per user and not one entry per “state” per user.
• This can be confusing however if the entity is using data class
. Most developer would expect by-property equality for data classes.
2️⃣ Equality by entity properties
• If I compare entire entities I can do neat things like checking if datasets have changed. If I have a val old: Collection<User>
and val new: Collection<User>
and want to check if there have been any updates between the two I can simply use old != new
. That’s useful for example for Flows and distinctUntilChanged()
.
• Developers may however run into unexpected behavior if for some reason sender
and recipient
refer to the same user (by ID) but one of the two instances has slightly different properties (e.g. due to a prior update). Because sender != recipient
reads so natural, that can be very unexpected.
There is a third option where you use either 1️⃣ or 2️⃣ and provide the other one as an additional entity function. That gets tricky however when you’re in a generic context and may not know enough about the type to call such a function, e.g. in a Flow<Collection<T>>.distinctUntilChanged { old, new -> … }
.
I’m curious, how do you usually do that in your codebases?diego-gomez-olvera
10/13/2020, 4:07 PM=
) with Unit
. In general I favor avoiding this and other people also found it confusing. Do you know if there is any kind of official guideline about it? https://kotlinlang.slack.com/archives/C4GKV43N2/p1506416194000224Dmitry Kandalov
10/14/2020, 10:12 PMor
function and I want to write something like this:
val json =
obj or
array or
string or
number
However, IDE formats it as:
val json =
obj or
array or
string or
number
And one line can be hard to read for a long list of chained functions:
val json = obj or array or string or number
KV
10/23/2020, 5:49 AMprivate fun setupPinKeypad() {
binding.pinCodeLayout.btn0.text = ZERO.toString()
binding.pinCodeLayout.btn1.text = ONE.toString()
binding.pinCodeLayout.btn2.text = TWO.toString()
binding.pinCodeLayout.btn3.text = THREE.toString()
binding.pinCodeLayout.btn4.text = FOUR.toString()
binding.pinCodeLayout.btn5.text = FIVE.toString()
binding.pinCodeLayout.btn6.text = SIX.toString()
binding.pinCodeLayout.btn7.text = SEVEN.toString()
binding.pinCodeLayout.btn8.text = EIGHT.toString()
binding.pinCodeLayout.btn9.text = NINE.toString()
}
KV
10/28/2020, 4:25 AMval filter: QueryFilter? = null
and I have one class like this ->
class QueryFilter(val by: String, val operator: String, val value: String)
And I am using the variable with class like this ->
filter.let {
mapOf(Pair("q[${<http://it.by|it.by>}_${it.operator}]", it.value))
} ?: emptyMap()
But now I have a variable like this
val filter: Array<QueryFilter> = emptyArray()
then how to use the loop with filter function with the same class?
I want to know that is this the correct way to write a code ? or Is there any better way to write the below code?
filter.let { it ->
it.forEach {
mapOf(Pair("q[${<http://it.by|it.by>}_${it.operator}]", it.value))
}
}
}) as Map<String, String>
Chris Black
10/30/2020, 4:26 PMcreate
function?
fun add(vararg s: String): String =
s.joinToString(" ")
fun create(one: String, two: String, three: String): String {
val m = mapOf(
one to "one case",
two to "two case",
three to "three case",
"" to ""
)
return add(m[one]!!, m[two]!!, m[three]!!)
}
orafaaraujo
11/18/2020, 6:05 PMwhen
when you can go with a simple if
But I can’t find it now… Does anyone knows where is it?Manuel Wrage
11/20/2020, 8:36 AMfun doSomething()
suspend fun doSomethingSuspending()
Manuel Wrage
11/20/2020, 8:36 AMfun doSomething()
suspend fun doSomethingSuspending()
elizarov
11/20/2020, 9:31 AMsuspend fun doSomething()
fun doSomethingBlocking()
Blocking
variant is more dangerous and, what's worse, can be called from anywhere (by mistake), so it must have a longer nameManuel Wrage
11/20/2020, 9:34 AM// fire and forget
fun dispatch(action: Action)
// dispatches the action and suspends until consumed
suspend fun dispatchSuspend(action: Action)
fun dispatch(action: Action): Deferred<Unit>
elizarov
11/20/2020, 9:51 AMdispatchAsync
to highlight the fact that it only starts the action, but does not wait for its completion in any way.Manuel Wrage
11/20/2020, 4:27 PM