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
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  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.

Grzegorz Ziemoński user avatar by
Grzegorz Ziemoński
·
Jun. 21, 17 · Tutorial
Like (17)
Save
Tweet
Share
17.51K Views

Join the DZone community and get the full member experience.

Join For Free

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.

Popular on DZone

  • How To Use Terraform to Provision an AWS EC2 Instance
  • How to Quickly Build an Audio Editor With UI
  • Building a Scalable Search Architecture
  • The 12 Biggest Android App Development Trends in 2023

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

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

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: