DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • The Window Closes: Why I Switched to Kotlin Before the Codebase Got Too Big
  • Testing Java and Spring Applications With Kotlin: Low-Risk to Adoption
  • Why Kotlin or Java Is the Wrong Question For Enterprises
  • Parallel Kafka Batch Processing With Kotlin Coroutines in Spring Boot

Trending

  • Claude Code Superpowers: The 5-Tool Stack That Ends Limits and Context Amnesia
  • Idempotency Under Concurrency: Why Your Application Check Isn't the Last Line of Defense
  • Mistaking Code Production for Engineering Progress: AI Productivity Myths Part 1
  • Building a Practical Cloud-Native Golden Path: A Guide to Kubernetes-Based Service Delivery, Self-Service, and Developer-Friendly Defaults

Draft This article hasn't been published, so readers can't see it.

In moderation This article is waiting for review, so readers can't see it yet.

Deleted This article has been deleted, so readers can't see it.

  1. DZone
  2. Coding
  3. Languages
  4. What Are Kotlin Progressions and Why Should You Care?

What Are Kotlin Progressions and Why Should You Care?

When writing for-loops over ranges in Kotlin, Progressions can help you incorporate types that aren't supported by default. Here's a guide tailored for Java devs.

By 
Grzegorz Ziemoński
·
Jun. 21, 17 · Tutorial
Post on X (opens in a new tab) Share on LinkedIn (opens in a new tab)
19.9K Views

Join the DZone community Save articles, join the discussion, and download Refcards and Trend Reports with a free account.

Join for free Already a member? Log in

Life Is Great

One of the first things that you notice when you start learning Kotlin is the "nice" for loop syntax that it has:

for (i in 1..5) { // mm, so fancy!
    println(i)
}


Cool, isn't it? An old, boring Java loop does not stand a chance.

for (int i = 0; i < 5; ++i) { // ugh, so boring!
    System.out.println(i);
}


As long as you stay in the world of trivial code samples or you iterate only over collections and ranges like the ones above, things are great. Kotlin is great, life is great, even politics don't bother you anymore.

Sad Times Arrive

Then, one day, you need to write a more sophisticated loop, say an equivalent of Java's:

LocalDate start = ...
LocalDate end = ...

for (LocalDate ld = start, !ld.isAfter(end); ld.plusDays(1)) {
    // stuff
}


"Ha, easy. I'll just switch to the Java-ish syntax and I'm fine", I thought in exactly such a case:

for (val ld = start; ld <= end; ld.plusDays(1)) {
    // stuff
}


An unpleasant surprise: There's no such construct in Kotlin! If you try to paste the snippet above to IntelliJ, it will automatically convert it to a while loop. Woops!

My next thought was: "Hey, there's this range syntax for dates that I used before. Maybe I can iterate over that..."

for (ld in start..end) {
    // stuff
}


Nope! That does not work either. At least not right away. As I learned a short while later, the secret of these nice Kotlin loops lies in the rangeTo operator and a bunch of base classes called Progressions.

RangeTo Operator

Whenever you type the double dot operator to create a nice range like "1..5" or "start..end", Kotlin translates the two dots in there into a call to the operator function called rangeTo.

As it turns out, Kotlin contains a few convenient implementations of the rangeTo operator for primitives and comparable types. The difference between the rangeTo for Int's and the rangeTo for LocalDate's is that the former returns an IntRange, while the latter returns a ClosedRange.

If you dig deeper into the implementation, you'll notice that IntRange extends a class called IntProgression, which in turn implements Iterable<Int>. That's the very reason why you can iterate over a range of Ints, while you cannot iterate over some other valid ranges of values.

Progressions

IntProgression is one of a few classes ending with the word Progression. The term denotes in Kotlin an Iterable that can use an arbitrary value as a step. You've probably seen already that in Kotlin you can do things like this:

for (i in 1..31 step 2) {
    println(i)
}


The step word here is nothing else than a call to an infix function called step, present in the IntProgression class. When you call this method, you get a new IntProgression with a step of requested size.

Our Very Own Progression

Now, equipped with all this valuable knowledge, we can finally solve our problem of iterating dates by implementing a progression ourselves!

class LocalDateProgression(override val start: LocalDate,
                           override val endInclusive: LocalDate,
                           val stepDays: Long = 1) : Iterable<LocalDate>, ClosedRange<LocalDate> {

    override fun iterator(): Iterator<LocalDate> = LocalDateProgressionIterator(start, endInclusive, stepDays)

    infix fun step(days: Long) = LocalDateProgression(start, endInclusive, days)
}


As you can see, there's no rocket science in there. Three parameters and trivial, one-line implementations and we have our very own, working progression. Obviously, we also need to implement the iterator that I've used in there:

internal class LocalDateProgressionIterator(start: LocalDate, val endInclusive: LocalDate, val stepDays: Long) : Iterator<LocalDate> {
    var current = start

    override fun hasNext() = current <= endInclusive

    override fun next(): LocalDate {
        val next = current
        current = current.plusDays(stepDays)
        return next
    }
}


And the last thing, we need to override the rangeTo operator for LocalDate, so that it uses our brand new progression:

operator fun LocalDate.rangeTo(other: LocalDate) = LocalDateProgression(this, other)


Tada!

for (ld in start..end step 2) { // mm, so fancy!
    println(ld)
}


Summary

As you can see, the for-loop over ranges in Kotlin is actually nothing magical. If your type is not supported by default, you can simply implement a new Progression, override the rangeTo operator, and your for-loops are fancy and shiny again. As for me, I'd actually prefer to be able to write a "normal" Java-ish for loop instead. "Ugh, so boring!"

Kotlin (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • The Window Closes: Why I Switched to Kotlin Before the Codebase Got Too Big
  • Testing Java and Spring Applications With Kotlin: Low-Risk to Adoption
  • Why Kotlin or Java Is the Wrong Question For Enterprises
  • Parallel Kafka Batch Processing With Kotlin Coroutines in Spring Boot

Partner Resources

×

Comments

Loading comments

The comments didn't load

Please try again in a moment.

Likes

Loading

The next likes didn't load. Please try again.

The likes didn't load

Please try again in a moment.

See who liked this

Log in or join DZone for free to see who liked this article.

Log in Join for free
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook