Hey! I know Kotlin has lazy properties with its de...
# getting-started
b
Hey! I know Kotlin has lazy properties with its delegates feature. Is there any way to add lazy evaluation (or, equivalently for my use case, memoization) such that the first time I call
foo(arg)
,
foo(arg)
gets calculated, but the second, third etc. times that I call
foo
after that,
foo(arg)
just returns the already computed, stored value. E.g. in Python, this exists in the form of the
@Memoize
operator, if anyone is familiar with that. Is there any way to achieve this in Kotlin or should I just implement the memoization mechanism myself.
j
There is no built-in feature for this. However, you could roll your own higher-order function to support it yourself. Something like
cached(key, args) { ... }
Doing this requires asking yourself lots of questions, though. Like how to synchronize things between threads, how to clean up the cache, etc.
Different use cases call for different solutions
y
Arrow has
MemoizedDeepRecursiveFunction
I believe, but yes you can just as well do your own higher-order function
🤔 1
b
Thanks for the replies! I've heard of Arrow from a thread talking about how its
Either<U,V>
behaves a lot like Rust's
Result<T,E>
enum or like TypeScript's union types; so Youssef, you've made me all the more curious about checking it out. Thanks, guys!
j
@Youssef Shoaib [MOD] how does arrow's cache eviction work? Does everything stay in memory forever? Are calls to this function thread-safe?
y
There's some basic built-in options, but also an integration module with cache-4k, which has all the cool cache eviction stuff you want. See https://arrow-kt.io/learn/collections-functions/recursive/
thank you color 3
j
Short sample of doing it yourself (which is honestly short enough to perhaps not worry about a shortcut):
Copy code
private val results = HashMap<Int, Int>()
fun memoizedFib(number: Int): Int = if(number <= 1) number else results.getOrPut(number) {
    memoizedFib(number - 1) + memoizedFib(number - 2)
}

memoizedFib(11)
Note this will have concurrency issues unless you use
ConcurrentHashMap
instead.
4
b
Hey, @joseph_ivie! Yeah, I've tried out the
getOrPut
way of doing things. It's fun :))
Question for the people in this thread: say I want to cache a function
foo(bar, baz, qux)
of three (or more) parameters. What's the most idiomatic way of doing it? I've perused [this StackOverflow answer](https://stackoverflow.com/questions/822322/how-to-implement-a-map-with-multiple-keys), and the idea of a MultiKeyMap seems enticing. I've tried just using a plain
MutableMap<Pair<K1, K2>,V>
, but maybe due to how pairs are hashed under the hood or something, it didn't have the expected / desired behaviour for my use case. So, would you implement
n
maps for a function that takes
n
arguments? Or is there a smarter approach to the underlying data structure here?
j
Contrary to the SO question you linked, you want the tuple to act as a single key, you don't want multiple independent keys. So the solution to have several non-nested maps will not work for you, but the single map with a pair (or list) as key should work. Could you please describe what you observed when you tried it?
b
Oh okay, maybe I did something wrong then. Let me double check and I'll get back to you with my issue if it persists.