louiscad
09/20/2021, 3:18 PMFun
fact: I took over 50 photos before I settled for the cover picture blob upside downelect
09/20/2021, 4:14 PMStephan Schroeder
09/21/2021, 1:32 PMPair
if you want to return to different types
fun getNameAndAge(): Pair<String, Int> = "Bob" to 42
val (name: String, age: Int) = getNameAndAge() // no danger of accidentally mixing up the order since it'd be a compiletime error
if the two types are the same, there's a danger of not knowing which is which
getUserNameAndPassword(): Pair<String, String> = "bob79" to "p4ssw0rd"
val (password, username) = getUserNameAndPassword() // oh no, wrong order
In that case either use a data class
but it's still possible to mess up order when using destructoring
class UsernamePassword(val username: String, val password: String)
getUserNameAndPassword() = UsernamePassword(
username="bob79",
password="p4ssw0rd",
)
val usernamePassword = getUserNameAndPassword()
val (password, username) = usernamePassword // oh no still wrong
// though long for is way less likely to be mistaken
val username = usernamePassword.username
val password = usernamePassword.password // way less likely to mess up
or you might use @JvmInline value class
to generate typesafe zero cost wrappers
@JvmInline value class Username(val value: String)
@JvmInline value class Password(val value: String)
fun getUserNameAndPassword(): Pair<Username, Password> = Username("Bob") to Password("p4ssw0rd")
val (username: Username, password: Password) = getUserNameAndPassword() // impossible to confuse (would be a compiletime error), zero overhead for the wrappers, single allocation of Pair, very readable
Readability basically always >> minimization of allocationselect
09/21/2021, 2:14 PMReadability basically always >> minimization of allocationsNot always, sorry. Anyway, it will be nice if Kotlin could provide a language construct for that
louiscad
09/21/2021, 5:28 PMStephan Schroeder
09/21/2021, 9:31 PMlouiscad
09/21/2021, 9:44 PMYoussef Shoaib [MOD]
10/04/2021, 1:37 PMfun main(){
val (stuff, bonus) = getStuff()
}
inline fun getStuff(): ZeroCostPair<Stuff, Bonus> {
val stuff = grabStuffFromCargoBikeBasket()
val bonus = inspirationElixir()
return ZeroCostPair(stuff, bonus)
}
//Implementation details
typealias ZeroCostPair<F, S> = (PairCall, F?, S?) -> Any?
enum class PairCall {
First,
Second
}
// Mimicking a constructor for the type.
inline fun <F, S> ZeroCostPair(first: F, second: S): ZeroCostPair<F, S> =
{ call, _, _ ->
when (call) {
PairCall.First -> first
PairCall.Second -> second
}
}
// Again, the parameters are useless, so just pass in null for them since during runtime the JVM won't actually know what
// F and S are since they get erased.
// We can safely cast the result of invoking the function as F or S because we know that ZeroCostPairs created using
// the factory function always follow the pattern of returning an F if PairCall.First is passed in and likewise for S.
inline val <F, S> ZeroCostPair<F, S>.first get() = this(PairCall.First, null, null) as F
inline val <F, S> ZeroCostPair<F, S>.second get() = this(PairCall.Second, null, null) as S