Hi folks, how would you write in kotlin a function...
# announcements
a
Hi folks, how would you write in kotlin a function that execute a function based on a percentage. Say for example you get a function to be called millions of times, and based on a param (the fixed percentage) you execute it. Something like: FunctionLimiter.execute(function, 10%) //function will be called only 10% of the times
n
Copy code
fun limiter(cb: () -> Unit, chance: Float) {
    if (Math.random() < chance) cb()
}
šŸ‘ 1
c
I’d just use
random.nextDouble()
and compare to your threshold. Using the same instance of Random over the entire process will ensure you have a uniform distribution
Copy code
val percentage = 0.1 // 10%
if(Random().nextDouble() <= percentage) { // nextDouble produces a value between 0.0 and 1.0
    doAThing()
}
And yeah, wrapping that logic up into a dedicated function is easy enough as well
a
and what if the function returns something and I don’t know what the return type is?
n
Copy code
fun <T> limiter(cb: () -> T, chance: Float): T {
    return if (Math.random() < chance) cb() else ???
}
I think you'd actually want
Random.nextDouble()
c
Copy code
fun <T: Any> limiter(doAThing: () -> T, percentage: Float, random: Random = Random.Default): T? {
    return if(random.nextDouble() >= percentage) doAThing() else null
}
šŸ‘ 1
It’s important to give the type parameter a bound of
: Any
so you know if the callback was used or not. A non-null value means it hit the callback, a null value means it did not. But you may want to wrap that in some result type for more semantic meaning, too
a
lovely thanks for your help guys!
n
could also provide a default value instead of null
a
Copy code
class PercentageLimiter {
    fun <T: Any> apply(function: () -> T): T {
        return function()
    }
}

class DoingSomething {
        fun doSomething(): String {
            return "hello world!"
        }
    }

PercentageLimiter().apply { return DoingSomething().doSomething() }
it seems I can’t return from apply
I see, it seems I can’t use return but if I don’t use it it returns ā€œhello worldā€, how come?
I'd suggest reading a bit about how returns, lambdas, inline, all interact
basically, lambdas cannot use a bare return statement, unless they are passed to an inline function, in which case the return refers to the outermost function
lambdas do return their last expression automatically though. or you can use a qualified/labelled return but this is rare
Check out the link though.
a
thanks a lot, so there is no side effect of avoiding return in the lambda
n
not sure what you mean by side effect šŸ™‚
but, if you mean "does it do the expected thing", then yes
a
ahah yeah that’s what I meant
n
but I would read that section, it's important to understand when to use
inline
on your functions that accept lambdas
and also how to use labelled returns when you actually do need them
a
I was reading about the inline functions but that behave even more differently
Copy code
limiter.apply {
            return DoingSomething().doSomething()
        }
If I do this, it expects a Unit as return and tells me return type mismatch, given string got Unit šŸ˜•
n
so if
apply
is inline, then just imagine that basically the contents of apply are inlined immediately, including the lambda invocation
so its like the lambda is being executed in the original function, so this returns from the outside function
but, again: read the link, it explains all this with examples.
a
ah now I get it, that’s why you can use labeled returns
n
yah. you can do things like
return@apply
or something like that
a
yah was reading it, I was just comparing with collection.ifEmpty where I can actually do ā€œreturnā€ as last statement of ā€œifEmptyā€
here instead it seems I almost never should use the return clause
n
i wouldn't say almost never, it really depends what you're doing
a
gotcha, thanks for the reference, will study it more in depth šŸ™‚
n
so a good example maybe where early returns are perfectly natural is in a
use
block
use
is an inline function
but it's not doing thsi entire complex operation for you... it's just introducing a scope where you have access to some resource, that closes automatically
it's perfectly reasonable that you may want to early return
Copy code
myfile.use {
    for (line in myFile) {
        if line == "ERROR!" {
            return
        }
    }
}
šŸ‘ 1
etc