I'm a long-time Java programmer, but recently I decided to give Kotlin a try. So far, I'm loving the language features, it feels much more expressive than what I'm used to. As practice, I wrote this function that produces a repeatable sequence of prime numbers (i.e. the sequence can be iterated multiple times, and will make use of results from past iterations to speed up future iterations). It feels pretty solid to me, but I'm wondering how it would look to a Kotlin veteran - are there language features that I'm not taking full advantage of, or conventions that I should be following?
One question I have in particular is regarding top-level function vs. subclass; here I chose to implement a top-level function primeSequence(): Sequence<Long>
that returns an object
, but I could have just about as easily implemented a class PrimeSequence : Sequence<Long>
. Is there a good rule of thumb for when to use one or the other?
fun primeSequence(): Sequence<Long> = object: Sequence<Long> {
private val knownPrimes: MutableList<Long> = arrayListOf(2L, 3L)
private fun Long.isMultipleOf(n: Long) = (this%n == 0L)
private fun Long.isPrime() = knownPrimes
.takeWhile { it*it <= this }
.none { this.isMultipleOf(it) }
override fun iterator(): Iterator<Long> = object: Iterator<Long> {
private var lastPrime: Long? = null
override fun hasNext() = true
override fun next(): Long {
val nextPrime = when(val lastPrime = this.lastPrime) {
null -> 2L
2L -> 3L
else -> {
if (knownPrimes.last() > lastPrime ) {
knownPrimes[knownPrimes.binarySearch(lastPrime) + 1]
} else {
val np = generateSequence(lastPrime+2) { it+2 }
.first { it.isPrime() }
knownPrimes.add(np)
np
}
}
}
this.lastPrime = nextPrime
return nextPrime
}
}
}